summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
Diffstat (limited to 'src/map')
-rw-r--r--src/map/GNUmakefile73
-rw-r--r--src/map/Makefile73
-rw-r--r--src/map/Makefile.win3293
-rw-r--r--src/map/atcommand.c7660
-rw-r--r--src/map/atcommand.h243
-rw-r--r--src/map/battle.c5387
-rw-r--r--src/map/battle.h345
-rw-r--r--src/map/chat.c373
-rw-r--r--src/map/chat.h22
-rw-r--r--src/map/chrif.c1016
-rw-r--r--src/map/chrif.h29
-rw-r--r--src/map/clif.c9712
-rw-r--r--src/map/clif.h297
-rw-r--r--src/map/guild.c1554
-rw-r--r--src/map/guild.h87
-rw-r--r--src/map/intif.c1119
-rw-r--r--src/map/intif.h60
-rw-r--r--src/map/itemdb.c882
-rw-r--r--src/map/itemdb.h84
-rw-r--r--src/map/log.c243
-rw-r--r--src/map/log.h27
-rw-r--r--src/map/mail.c324
-rw-r--r--src/map/mail.h9
-rw-r--r--src/map/map.c2208
-rw-r--r--src/map/map.h724
-rw-r--r--src/map/mob.c4269
-rw-r--r--src/map/mob.h139
-rw-r--r--src/map/npc.c2274
-rw-r--r--src/map/npc.h52
-rw-r--r--src/map/party.c644
-rw-r--r--src/map/party.h47
-rw-r--r--src/map/path.c404
-rw-r--r--src/map/pc.c7499
-rw-r--r--src/map/pc.h186
-rw-r--r--src/map/pet.c1651
-rw-r--r--src/map/pet.h69
-rw-r--r--src/map/script.c6769
-rw-r--r--src/map/script.h39
-rw-r--r--src/map/skill.c10682
-rw-r--r--src/map/skill.h854
-rw-r--r--src/map/storage.c595
-rw-r--r--src/map/storage.h39
-rw-r--r--src/map/trade.c286
-rw-r--r--src/map/trade.h13
-rw-r--r--src/map/vending.c170
-rw-r--r--src/map/vending.h12
46 files changed, 69337 insertions, 0 deletions
diff --git a/src/map/GNUmakefile b/src/map/GNUmakefile
new file mode 100644
index 000000000..a1a68d107
--- /dev/null
+++ b/src/map/GNUmakefile
@@ -0,0 +1,73 @@
+all: txt sql
+
+txt: txtobj map-server
+
+sql: sqlobj map-server_sql
+
+txtobj:
+ mkdir txtobj
+
+sqlobj:
+ mkdir sqlobj
+
+COMMON_OBJ = ../common/core.o ../common/socket.o ../common/timer.o ../common/grfio.o ../common/db.o ../common/lock.o ../common/nullpo.o ../common/malloc.o ../common/showmsg.o
+LIBS = -lz -lm
+
+map-server: txtobj/map.o txtobj/chrif.o txtobj/clif.o txtobj/pc.o txtobj/npc.o txtobj/chat.o txtobj/path.o txtobj/itemdb.o txtobj/mob.o txtobj/script.o txtobj/storage.o txtobj/skill.o txtobj/atcommand.o txtobj/battle.o txtobj/intif.o txtobj/trade.o txtobj/party.o txtobj/vending.o txtobj/guild.o txtobj/pet.o $(COMMON_OBJ)
+ $(CC) -o ../../$@ $^ $(LIBS)
+
+map-server_sql: sqlobj/map.o sqlobj/chrif.o sqlobj/clif.o sqlobj/pc.o sqlobj/npc.o sqlobj/chat.o sqlobj/path.o sqlobj/itemdb.o sqlobj/mob.o sqlobj/script.o sqlobj/storage.o sqlobj/skill.o sqlobj/atcommand.o sqlobj/battle.o sqlobj/intif.o sqlobj/trade.o sqlobj/party.o sqlobj/vending.o sqlobj/guild.o sqlobj/pet.o sqlobj/mail.o sqlobj/log.o $(COMMON_OBJ)
+ $(CC) -o ../../$@ $^ $(LIB_S)
+
+txtobj/%.o: %.c
+ $(COMPILE.c) -DTXT_ONLY $(OUTPUT_OPTION) $<
+
+sqlobj/%.o: %.c
+ $(COMPILE.c) $(OUTPUT_OPTION) $<
+
+txtobj/map.o: map.c map.h chrif.h clif.h npc.h pc.h mob.h chat.h skill.h itemdb.h storage.h party.h pet.h atcommand.h ../common/core.h ../common/timer.h ../common/db.h ../common/grfio.h ../common/mmo.h ../common/showmsg.h
+txtobj/chrif.o: chrif.c map.h battle.h chrif.h clif.h intif.h pc.h npc.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/clif.o: clif.c map.h chrif.h clif.h mob.h intif.h pc.h npc.h itemdb.h chat.h script.h storage.h party.h guild.h atcommand.h pet.h atcommand.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/version.h ../common/showmsg.h
+txtobj/pc.o: pc.c map.h clif.h intif.h pc.h npc.h mob.h itemdb.h battle.h skill.h script.h party.h guild.h pet.h trade.h storage.h chat.h vending.h ../common/timer.h ../common/mmo.h ../common/db.h ../common/showmsg.h
+txtobj/npc.o: npc.c map.h npc.h clif.h pc.h script.h mob.h itemdb.h battle.h ../common/db.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/chat.o: chat.c map.h clif.h pc.h chat.h ../common/db.h ../common/mmo.h ../common/showmsg.h
+txtobj/path.o: path.c map.h battle.h ../common/mmo.h ../common/showmsg.h
+txtobj/itemdb.o: itemdb.c map.h battle.h itemdb.h ../common/db.h ../common/grfio.h ../common/mmo.h ../common/showmsg.h
+txtobj/mob.o: mob.c map.h clif.h intif.h pc.h mob.h skill.h battle.h npc.h itemdb.h ../common/timer.h ../common/socket.h ../common/mmo.h ../common/showmsg.h
+txtobj/script.o: script.c itemdb.h map.h pc.h mob.h clif.h intif.h npc.h script.h storage.h skill.h pet.h battle.h ../common/timer.h ../common/socket.h ../common/db.h ../common/mmo.h ../common/lock.h ../common/showmsg.h
+txtobj/storage.o: storage.c itemdb.h pc.h clif.h intif.h storage.h guild.h ../common/mmo.h ../common/db.h ../common/showmsg.h
+txtobj/skill.o: skill.c skill.h map.h clif.h pc.h mob.h battle.h itemdb.h script.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/atcommand.o: atcommand.c atcommand.h itemdb.h pc.h map.h skill.h clif.h mob.h intif.h battle.h storage.h guild.h pet.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/battle.o: battle.c battle.h skill.h map.h mob.h pc.h pet.h guild.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/intif.o: intif.c intif.h chrif.h clif.h party.h guild.h storage.h map.h battle.h pet.h ../common/socket.h ../common/mmo.h ../common/showmsg.h
+txtobj/trade.o: trade.c trade.h clif.h itemdb.h map.h pc.h npc.h ../common/mmo.h ../common/showmsg.h
+txtobj/party.o: party.c party.h clif.h intif.h pc.h map.h battle.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/vending.o: vending.c vending.h clif.h itemdb.h map.h pc.h ../common/mmo.h ../common/showmsg.h
+txtobj/guild.o: guild.c guild.h storage.h battle.h clif.h intif.h pc.h npc.h map.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/pet.o: pet.c pet.h map.h clif.h chrif.h intif.h pc.h itemdb.h battle.h mob.h npc.h script.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+
+sqlobj/map.o: map.c map.h chrif.h clif.h npc.h pc.h mob.h chat.h skill.h itemdb.h storage.h party.h pet.h atcommand.h log.h ../common/core.h ../common/timer.h ../common/db.h ../common/grfio.h ../common/mmo.h ../common/showmsg.h
+sqlobj/chrif.o: chrif.c map.h battle.h chrif.h clif.h intif.h pc.h npc.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/clif.o: clif.c map.h chrif.h clif.h mob.h intif.h pc.h npc.h itemdb.h chat.h script.h storage.h party.h guild.h atcommand.h pet.h atcommand.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/version.h ../common/showmsg.h
+sqlobj/pc.o: pc.c map.h clif.h intif.h pc.h npc.h mob.h itemdb.h battle.h skill.h script.h party.h guild.h pet.h trade.h storage.h chat.h vending.h log.h ../common/timer.h ../common/mmo.h ../common/db.h ../common/showmsg.h
+sqlobj/npc.o: npc.c map.h npc.h clif.h pc.h script.h mob.h itemdb.h battle.h ../common/db.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/chat.o: chat.c map.h clif.h pc.h chat.h ../common/db.h ../common/mmo.h ../common/showmsg.h
+sqlobj/path.o: path.c map.h battle.h ../common/mmo.h ../common/showmsg.h
+sqlobj/itemdb.o: itemdb.c map.h battle.h itemdb.h ../common/db.h ../common/grfio.h ../common/mmo.h ../common/showmsg.h
+sqlobj/mob.o: mob.c map.h clif.h intif.h pc.h mob.h skill.h battle.h npc.h itemdb.h log.h ../common/timer.h ../common/socket.h ../common/mmo.h ../common/showmsg.h
+sqlobj/script.o: script.c itemdb.h map.h pc.h mob.h clif.h intif.h npc.h script.h storage.h skill.h pet.h battle.h log.h ../common/timer.h ../common/socket.h ../common/db.h ../common/mmo.h ../common/lock.h ../common/showmsg.h
+sqlobj/storage.o: storage.c itemdb.h pc.h clif.h intif.h storage.h guild.h ../common/mmo.h ../common/db.h ../common/showmsg.h
+sqlobj/skill.o: skill.c skill.h map.h clif.h pc.h mob.h battle.h itemdb.h script.h log.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/atcommand.o: atcommand.c atcommand.h itemdb.h pc.h map.h skill.h clif.h mob.h intif.h battle.h storage.h guild.h pet.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/battle.o: battle.c battle.h skill.h map.h mob.h pc.h pet.h guild.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/intif.o: intif.c intif.h chrif.h clif.h party.h guild.h storage.h map.h battle.h pet.h ../common/socket.h ../common/mmo.h ../common/showmsg.h
+sqlobj/trade.o: trade.c trade.h clif.h itemdb.h map.h pc.h npc.h log.h ../common/mmo.h ../common/showmsg.h
+sqlobj/party.o: party.c party.h clif.h intif.h pc.h map.h battle.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/vending.o: vending.c vending.h clif.h itemdb.h map.h pc.h log.h ../common/mmo.h ../common/showmsg.h
+sqlobj/guild.o: guild.c guild.h storage.h battle.h clif.h intif.h pc.h npc.h map.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/pet.o: pet.c pet.h map.h clif.h chrif.h intif.h pc.h itemdb.h battle.h mob.h npc.h script.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/mail.o: mail.c mail.h ../common/showmsg.h
+sqlobj/log.o: log.c log.h map.h ../common/nullpo.h
+
+clean:
+ rm -rf *.o ../../map-server ../../map-server_sql sqlobj txtobj
diff --git a/src/map/Makefile b/src/map/Makefile
new file mode 100644
index 000000000..cc5abc73c
--- /dev/null
+++ b/src/map/Makefile
@@ -0,0 +1,73 @@
+all: txt sql
+
+txt: txtobj map-server
+
+sql: sqlobj map-server_sql
+
+txtobj:
+ mkdir txtobj
+
+sqlobj:
+ mkdir sqlobj
+
+COMMON_OBJ = ../common/core.o ../common/socket.o ../common/timer.o ../common/grfio.o ../common/db.o ../common/lock.o ../common/nullpo.o ../common/malloc.o ../common/showmsg.o
+LIBS = -lz -lm
+
+map-server: txtobj/map.o txtobj/chrif.o txtobj/clif.o txtobj/pc.o txtobj/npc.o txtobj/chat.o txtobj/path.o txtobj/itemdb.o txtobj/mob.o txtobj/script.o txtobj/storage.o txtobj/skill.o txtobj/atcommand.o txtobj/battle.o txtobj/intif.o txtobj/trade.o txtobj/party.o txtobj/vending.o txtobj/guild.o txtobj/pet.o $(COMMON_OBJ)
+ $(CC) -o ../../$@ $> $(LIBS)
+
+map-server_sql: sqlobj/map.o sqlobj/chrif.o sqlobj/clif.o sqlobj/pc.o sqlobj/npc.o sqlobj/chat.o sqlobj/path.o sqlobj/itemdb.o sqlobj/mob.o sqlobj/script.o sqlobj/storage.o sqlobj/skill.o sqlobj/atcommand.o sqlobj/battle.o sqlobj/intif.o sqlobj/trade.o sqlobj/party.o sqlobj/vending.o sqlobj/guild.o sqlobj/pet.o sqlobj/mail.o sqlobj/log.o $(COMMON_OBJ)
+ $(CC) -o ../../$@ $> $(LIB_S)
+
+txtobj/%.o: %.c
+ $(COMPILE.c) -DTXT_ONLY $(OUTPUT_OPTION) $<
+
+sqlobj/%.o: %.c
+ $(COMPILE.c) $(OUTPUT_OPTION) $<
+
+txtobj/map.o: map.c map.h chrif.h clif.h npc.h pc.h mob.h chat.h skill.h itemdb.h storage.h party.h pet.h atcommand.h ../common/core.h ../common/timer.h ../common/db.h ../common/grfio.h ../common/mmo.h ../common/showmsg.h
+txtobj/chrif.o: chrif.c map.h battle.h chrif.h clif.h intif.h pc.h npc.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/clif.o: clif.c map.h chrif.h clif.h mob.h intif.h pc.h npc.h itemdb.h chat.h script.h storage.h party.h guild.h atcommand.h pet.h atcommand.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/version.h ../common/showmsg.h
+txtobj/pc.o: pc.c map.h clif.h intif.h pc.h npc.h mob.h itemdb.h battle.h skill.h script.h party.h guild.h pet.h trade.h storage.h chat.h vending.h ../common/timer.h ../common/mmo.h ../common/db.h ../common/showmsg.h
+txtobj/npc.o: npc.c map.h npc.h clif.h pc.h script.h mob.h itemdb.h battle.h ../common/db.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/chat.o: chat.c map.h clif.h pc.h chat.h ../common/db.h ../common/mmo.h ../common/showmsg.h
+txtobj/path.o: path.c map.h battle.h ../common/mmo.h ../common/showmsg.h
+txtobj/itemdb.o: itemdb.c map.h battle.h itemdb.h ../common/db.h ../common/grfio.h ../common/mmo.h ../common/showmsg.h
+txtobj/mob.o: mob.c map.h clif.h intif.h pc.h mob.h skill.h battle.h npc.h itemdb.h ../common/timer.h ../common/socket.h ../common/mmo.h ../common/showmsg.h
+txtobj/script.o: script.c itemdb.h map.h pc.h mob.h clif.h intif.h npc.h script.h storage.h skill.h pet.h battle.h ../common/timer.h ../common/socket.h ../common/db.h ../common/mmo.h ../common/lock.h ../common/showmsg.h
+txtobj/storage.o: storage.c itemdb.h pc.h clif.h intif.h storage.h guild.h ../common/mmo.h ../common/db.h ../common/showmsg.h
+txtobj/skill.o: skill.c skill.h map.h clif.h pc.h mob.h battle.h itemdb.h script.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/atcommand.o: atcommand.c atcommand.h itemdb.h pc.h map.h skill.h clif.h mob.h intif.h battle.h storage.h guild.h pet.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/battle.o: battle.c battle.h skill.h map.h mob.h pc.h pet.h guild.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/intif.o: intif.c intif.h chrif.h clif.h party.h guild.h storage.h map.h battle.h pet.h ../common/socket.h ../common/mmo.h ../common/showmsg.h
+txtobj/trade.o: trade.c trade.h clif.h itemdb.h map.h pc.h npc.h ../common/mmo.h ../common/showmsg.h
+txtobj/party.o: party.c party.h clif.h intif.h pc.h map.h battle.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/vending.o: vending.c vending.h clif.h itemdb.h map.h pc.h ../common/mmo.h ../common/showmsg.h
+txtobj/guild.o: guild.c guild.h storage.h battle.h clif.h intif.h pc.h npc.h map.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/pet.o: pet.c pet.h map.h clif.h chrif.h intif.h pc.h itemdb.h battle.h mob.h npc.h script.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+
+sqlobj/map.o: map.c map.h chrif.h clif.h npc.h pc.h mob.h chat.h skill.h itemdb.h storage.h party.h pet.h atcommand.h log.h ../common/core.h ../common/timer.h ../common/db.h ../common/grfio.h ../common/mmo.h ../common/showmsg.h
+sqlobj/chrif.o: chrif.c map.h battle.h chrif.h clif.h intif.h pc.h npc.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/clif.o: clif.c map.h chrif.h clif.h mob.h intif.h pc.h npc.h itemdb.h chat.h script.h storage.h party.h guild.h atcommand.h pet.h atcommand.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/version.h ../common/showmsg.h
+sqlobj/pc.o: pc.c map.h clif.h intif.h pc.h npc.h mob.h itemdb.h battle.h skill.h script.h party.h guild.h pet.h trade.h storage.h chat.h vending.h log.h ../common/timer.h ../common/mmo.h ../common/db.h ../common/showmsg.h
+sqlobj/npc.o: npc.c map.h npc.h clif.h pc.h script.h mob.h itemdb.h battle.h ../common/db.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/chat.o: chat.c map.h clif.h pc.h chat.h ../common/db.h ../common/mmo.h ../common/showmsg.h
+sqlobj/path.o: path.c map.h battle.h ../common/mmo.h ../common/showmsg.h
+sqlobj/itemdb.o: itemdb.c map.h battle.h itemdb.h ../common/db.h ../common/grfio.h ../common/mmo.h ../common/showmsg.h
+sqlobj/mob.o: mob.c map.h clif.h intif.h pc.h mob.h skill.h battle.h npc.h itemdb.h log.h ../common/timer.h ../common/socket.h ../common/mmo.h ../common/showmsg.h
+sqlobj/script.o: script.c itemdb.h map.h pc.h mob.h clif.h intif.h npc.h script.h storage.h skill.h pet.h battle.h log.h ../common/timer.h ../common/socket.h ../common/db.h ../common/mmo.h ../common/lock.h ../common/showmsg.h
+sqlobj/storage.o: storage.c itemdb.h pc.h clif.h intif.h storage.h guild.h ../common/mmo.h ../common/db.h ../common/showmsg.h
+sqlobj/skill.o: skill.c skill.h map.h clif.h pc.h mob.h battle.h itemdb.h script.h log.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/atcommand.o: atcommand.c atcommand.h itemdb.h pc.h map.h skill.h clif.h mob.h intif.h battle.h storage.h guild.h pet.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/battle.o: battle.c battle.h skill.h map.h mob.h pc.h pet.h guild.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/intif.o: intif.c intif.h chrif.h clif.h party.h guild.h storage.h map.h battle.h pet.h ../common/socket.h ../common/mmo.h ../common/showmsg.h
+sqlobj/trade.o: trade.c trade.h clif.h itemdb.h map.h pc.h npc.h log.h ../common/mmo.h ../common/showmsg.h
+sqlobj/party.o: party.c party.h clif.h intif.h pc.h map.h battle.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/vending.o: vending.c vending.h clif.h itemdb.h map.h pc.h log.h ../common/mmo.h ../common/showmsg.h
+sqlobj/guild.o: guild.c guild.h storage.h battle.h clif.h intif.h pc.h npc.h map.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/pet.o: pet.c pet.h map.h clif.h chrif.h intif.h pc.h itemdb.h battle.h mob.h npc.h script.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/mail.o: mail.c mail.h ../common/showmsg.h
+sqlobj/log.o: log.c log.h map.h ../common/nullpo.h
+
+clean:
+ rm -rf *.o ../../map-server ../../map-server_sql sqlobj txtobj
diff --git a/src/map/Makefile.win32 b/src/map/Makefile.win32
new file mode 100644
index 000000000..df6782c84
--- /dev/null
+++ b/src/map/Makefile.win32
@@ -0,0 +1,93 @@
+# grab a copy of http://www.winimage.com/zLibDll/zlib122.zip
+# and put safely into a subdirectory someplace
+# then point ZLIBDIR at whereever you put it
+#
+
+all: txt sql
+
+txt: txtobj map-server
+
+sql: sqlobj map-server_sql
+
+txtobj:
+ mkdir txtobj
+
+sqlobj:
+ mkdir sqlobj
+
+ZLIBDIR = C:/athena/zlib122
+PACKETDEF = -DPACKETVER=5 -DNEW_006b
+# OPT = /MDd /D_DEBUG
+OPT =
+LINKOPT = /debug /SUBSYSTEM:CONSOLE
+# OPT = /O2
+CFLAGS = $(OPT) /nologo /I../common /I$(ZLIBDIR) $(PACKETDEF) /D_WIN32
+
+COMMON_OBJ = ../common/core.o ../common/socket.o ../common/timer.o ../common/grfio.o ../common/db.o ../common/lock.o ../common/nullpo.o ../common/malloc.o ../common/showmsg.o
+LIBS = "WSOCK32.LIB"
+
+# "WSOCK32.LIB" "USER32.LIB" "ADVAPI32.LIB" "MSVCRT.LIB" "OLDNAMES.LIB" "KERNEL32.LIB"
+
+TXTOBJS = txtobj/map.o txtobj/chrif.o txtobj/clif.o txtobj/pc.o txtobj/npc.o txtobj/chat.o txtobj/path.o txtobj/itemdb.o txtobj/mob.o txtobj/script.o txtobj/storage.o txtobj/skill.o txtobj/atcommand.o txtobj/battle.o txtobj/intif.o txtobj/trade.o txtobj/party.o txtobj/vending.o txtobj/guild.o txtobj/pet.o $(COMMON_OBJ) $(ZLIBDIR)/inflate.o $(ZLIBDIR)/adler32.o $(ZLIBDIR)/crc32.o $(ZLIBDIR)/inftrees.o $(ZLIBDIR)/zutil.o $(ZLIBDIR)/inffast.o
+
+map-server: $(TXTOBJS)
+ link $(LINKOPT) /out:../../$@.exe $(TXTOBJS) $(LIBS)
+
+map-server_sql: sqlobj/map.o sqlobj/chrif.o sqlobj/clif.o sqlobj/pc.o sqlobj/npc.o sqlobj/chat.o sqlobj/path.o sqlobj/itemdb.o sqlobj/mob.o sqlobj/script.o sqlobj/storage.o sqlobj/skill.o sqlobj/atcommand.o sqlobj/battle.o sqlobj/intif.o sqlobj/trade.o sqlobj/party.o sqlobj/vending.o sqlobj/guild.o sqlobj/pet.o sqlobj/mail.o $(COMMON_OBJ)
+ link $(LINKOPT) /out:../../$@.exe $> $(LIBS)
+
+txtobj/%.o: %.c
+ Cl /c $(CFLAGS) -DTXT_ONLY /Fo$@ $<
+
+sqlobj/%.o: %.c
+ Cl /c $(CFLAGS) /Fo$@ $<
+
+%.o: %.c
+ Cl /c $(CFLAGS) /Fo$@ $<
+
+txtobj/map.o: map.c map.h chrif.h clif.h npc.h pc.h mob.h chat.h skill.h itemdb.h storage.h party.h pet.h atcommand.h ../common/core.h ../common/timer.h ../common/db.h ../common/grfio.h ../common/mmo.h ../common/showmsg.h
+txtobj/chrif.o: chrif.c map.h battle.h chrif.h clif.h intif.h pc.h npc.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/clif.o: clif.c map.h chrif.h clif.h mob.h intif.h pc.h npc.h itemdb.h chat.h script.h storage.h party.h guild.h atcommand.h pet.h atcommand.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/version.h ../common/showmsg.h
+txtobj/pc.o: pc.c map.h clif.h intif.h pc.h npc.h mob.h itemdb.h battle.h skill.h script.h party.h guild.h pet.h trade.h storage.h chat.h vending.h ../common/timer.h ../common/mmo.h ../common/db.h ../common/showmsg.h
+txtobj/npc.o: npc.c map.h npc.h clif.h pc.h script.h mob.h itemdb.h battle.h ../common/db.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/chat.o: chat.c map.h clif.h pc.h chat.h ../common/db.h ../common/mmo.h ../common/showmsg.h
+txtobj/path.o: path.c map.h battle.h ../common/mmo.h ../common/showmsg.h
+txtobj/itemdb.o: itemdb.c map.h battle.h itemdb.h ../common/db.h ../common/grfio.h ../common/mmo.h ../common/showmsg.h
+txtobj/mob.o: mob.c map.h clif.h intif.h pc.h mob.h skill.h battle.h npc.h itemdb.h ../common/timer.h ../common/socket.h ../common/mmo.h ../common/showmsg.h
+txtobj/script.o: script.c itemdb.h map.h pc.h mob.h clif.h intif.h npc.h script.h storage.h skill.h pet.h battle.h ../common/timer.h ../common/socket.h ../common/db.h ../common/mmo.h ../common/lock.h ../common/showmsg.h
+txtobj/storage.o: storage.c itemdb.h pc.h clif.h intif.h storage.h guild.h ../common/mmo.h ../common/db.h ../common/showmsg.h
+txtobj/skill.o: skill.c skill.h map.h clif.h pc.h mob.h battle.h itemdb.h script.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/atcommand.o: atcommand.c atcommand.h itemdb.h pc.h map.h skill.h clif.h mob.h intif.h battle.h storage.h guild.h pet.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/battle.o: battle.c battle.h skill.h map.h mob.h pc.h pet.h guild.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/intif.o: intif.c intif.h chrif.h clif.h party.h guild.h storage.h map.h battle.h pet.h ../common/socket.h ../common/mmo.h ../common/showmsg.h
+txtobj/trade.o: trade.c trade.h clif.h itemdb.h map.h pc.h npc.h ../common/mmo.h ../common/showmsg.h
+txtobj/party.o: party.c party.h clif.h intif.h pc.h map.h battle.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/vending.o: vending.c vending.h clif.h itemdb.h map.h pc.h ../common/mmo.h ../common/showmsg.h
+txtobj/guild.o: guild.c guild.h storage.h battle.h clif.h intif.h pc.h npc.h map.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+txtobj/pet.o: pet.c pet.h map.h clif.h chrif.h intif.h pc.h itemdb.h battle.h mob.h npc.h script.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+
+sqlobj/map.o: map.c map.h chrif.h clif.h npc.h pc.h mob.h chat.h skill.h itemdb.h storage.h party.h pet.h atcommand.h log.h ../common/core.h ../common/timer.h ../common/db.h ../common/grfio.h ../common/mmo.h ../common/showmsg.h
+sqlobj/chrif.o: chrif.c map.h battle.h chrif.h clif.h intif.h pc.h npc.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/clif.o: clif.c map.h chrif.h clif.h mob.h intif.h pc.h npc.h itemdb.h chat.h script.h storage.h party.h guild.h atcommand.h pet.h atcommand.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/version.h ../common/showmsg.h
+sqlobj/pc.o: pc.c map.h clif.h intif.h pc.h npc.h mob.h itemdb.h battle.h skill.h script.h party.h guild.h pet.h trade.h storage.h chat.h vending.h log.h ../common/timer.h ../common/mmo.h ../common/db.h ../common/showmsg.h
+sqlobj/npc.o: npc.c map.h npc.h clif.h pc.h script.h mob.h itemdb.h battle.h ../common/db.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/chat.o: chat.c map.h clif.h pc.h chat.h ../common/db.h ../common/mmo.h ../common/showmsg.h
+sqlobj/path.o: path.c map.h battle.h ../common/mmo.h ../common/showmsg.h
+sqlobj/itemdb.o: itemdb.c map.h battle.h itemdb.h ../common/db.h ../common/grfio.h ../common/mmo.h ../common/showmsg.h
+sqlobj/mob.o: mob.c map.h clif.h intif.h pc.h mob.h skill.h battle.h npc.h itemdb.h log.h ../common/timer.h ../common/socket.h ../common/mmo.h ../common/showmsg.h
+sqlobj/script.o: script.c itemdb.h map.h pc.h mob.h clif.h intif.h npc.h script.h storage.h skill.h pet.h battle.h log.h ../common/timer.h ../common/socket.h ../common/db.h ../common/mmo.h ../common/lock.h ../common/showmsg.h
+sqlobj/storage.o: storage.c itemdb.h pc.h clif.h intif.h storage.h guild.h ../common/mmo.h ../common/db.h ../common/showmsg.h
+sqlobj/skill.o: skill.c skill.h map.h clif.h pc.h mob.h battle.h itemdb.h script.h log.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/atcommand.o: atcommand.c atcommand.h itemdb.h pc.h map.h skill.h clif.h mob.h intif.h battle.h storage.h guild.h pet.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/battle.o: battle.c battle.h skill.h map.h mob.h pc.h pet.h guild.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/intif.o: intif.c intif.h chrif.h clif.h party.h guild.h storage.h map.h battle.h pet.h ../common/socket.h ../common/mmo.h ../common/showmsg.h
+sqlobj/trade.o: trade.c trade.h clif.h itemdb.h map.h pc.h npc.h log.h ../common/mmo.h ../common/showmsg.h
+sqlobj/party.o: party.c party.h clif.h intif.h pc.h map.h battle.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/vending.o: vending.c vending.h clif.h itemdb.h map.h pc.h log.h ../common/mmo.h ../common/showmsg.h
+sqlobj/guild.o: guild.c guild.h storage.h battle.h clif.h intif.h pc.h npc.h map.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/pet.o: pet.c pet.h map.h clif.h chrif.h intif.h pc.h itemdb.h battle.h mob.h npc.h script.h ../common/db.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/showmsg.h
+sqlobj/mail.o: mail.c mail.h ../common/showmsg.h
+sqlobj/log.o: log.c log.h map.h ../common/nullpo.h
+
+clean:
+ rm -rf *.o ../../map-server ../../map-server_sql sqlobj txtobj
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
new file mode 100644
index 000000000..a4c6fc745
--- /dev/null
+++ b/src/map/atcommand.c
@@ -0,0 +1,7660 @@
+// $Id: atcommand.c 148 2004-09-30 14:05:37Z MouseJstr $
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+#include "socket.h"
+#include "timer.h"
+#include "nullpo.h"
+
+#include "clif.h"
+#include "chrif.h"
+#include "intif.h"
+#include "itemdb.h"
+#include "map.h"
+#include "pc.h"
+#include "skill.h"
+#include "mob.h"
+#include "pet.h"
+#include "battle.h"
+#include "party.h"
+#include "guild.h"
+#include "atcommand.h"
+#include "script.h"
+#include "npc.h"
+#include "trade.h"
+#include "core.h"
+
+#ifndef TXT_ONLY
+#include "mail.h"
+#endif
+
+#define STATE_BLIND 0x10
+
+static char command_symbol = '@'; // first char of the commands (by [Yor])
+
+static char msg_table[1000][1024]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others)
+
+#define ATCOMMAND_FUNC(x) int atcommand_ ## x (const int fd, struct map_session_data* sd, const char* command, const char* message)
+ATCOMMAND_FUNC(broadcast);
+ATCOMMAND_FUNC(localbroadcast);
+ATCOMMAND_FUNC(rurap);
+ATCOMMAND_FUNC(rura);
+ATCOMMAND_FUNC(where);
+ATCOMMAND_FUNC(jumpto);
+ATCOMMAND_FUNC(jump);
+ATCOMMAND_FUNC(who);
+ATCOMMAND_FUNC(who2);
+ATCOMMAND_FUNC(who3);
+ATCOMMAND_FUNC(whomap);
+ATCOMMAND_FUNC(whomap2);
+ATCOMMAND_FUNC(whomap3);
+ATCOMMAND_FUNC(whogm); // by Yor
+ATCOMMAND_FUNC(save);
+ATCOMMAND_FUNC(load);
+ATCOMMAND_FUNC(speed);
+ATCOMMAND_FUNC(storage);
+ATCOMMAND_FUNC(guildstorage);
+ATCOMMAND_FUNC(option);
+ATCOMMAND_FUNC(hide);
+ATCOMMAND_FUNC(jobchange);
+ATCOMMAND_FUNC(die);
+ATCOMMAND_FUNC(kill);
+ATCOMMAND_FUNC(alive);
+ATCOMMAND_FUNC(kami);
+ATCOMMAND_FUNC(heal);
+ATCOMMAND_FUNC(item);
+ATCOMMAND_FUNC(item2);
+ATCOMMAND_FUNC(itemreset);
+ATCOMMAND_FUNC(itemcheck);
+ATCOMMAND_FUNC(baselevelup);
+ATCOMMAND_FUNC(joblevelup);
+ATCOMMAND_FUNC(help);
+ATCOMMAND_FUNC(gm);
+ATCOMMAND_FUNC(pvpoff);
+ATCOMMAND_FUNC(pvpon);
+ATCOMMAND_FUNC(gvgoff);
+ATCOMMAND_FUNC(gvgon);
+ATCOMMAND_FUNC(model);
+ATCOMMAND_FUNC(go);
+ATCOMMAND_FUNC(monster);
+ATCOMMAND_FUNC(spawn);
+ATCOMMAND_FUNC(killmonster);
+ATCOMMAND_FUNC(killmonster2);
+ATCOMMAND_FUNC(refine);
+ATCOMMAND_FUNC(produce);
+ATCOMMAND_FUNC(memo);
+ATCOMMAND_FUNC(gat);
+ATCOMMAND_FUNC(packet);
+ATCOMMAND_FUNC(statuspoint);
+ATCOMMAND_FUNC(skillpoint);
+ATCOMMAND_FUNC(zeny);
+ATCOMMAND_FUNC(param);
+ATCOMMAND_FUNC(guildlevelup);
+ATCOMMAND_FUNC(makeegg);
+ATCOMMAND_FUNC(hatch);
+ATCOMMAND_FUNC(petfriendly);
+ATCOMMAND_FUNC(pethungry);
+ATCOMMAND_FUNC(petrename);
+ATCOMMAND_FUNC(charpetrename); // by Yor
+ATCOMMAND_FUNC(recall);
+ATCOMMAND_FUNC(recallall);
+ATCOMMAND_FUNC(character_job);
+ATCOMMAND_FUNC(revive);
+ATCOMMAND_FUNC(character_stats);
+ATCOMMAND_FUNC(character_stats_all);
+ATCOMMAND_FUNC(character_option);
+ATCOMMAND_FUNC(character_save);
+ATCOMMAND_FUNC(night);
+ATCOMMAND_FUNC(day);
+ATCOMMAND_FUNC(doom);
+ATCOMMAND_FUNC(doommap);
+ATCOMMAND_FUNC(raise);
+ATCOMMAND_FUNC(raisemap);
+ATCOMMAND_FUNC(character_baselevel);
+ATCOMMAND_FUNC(character_joblevel);
+ATCOMMAND_FUNC(kick);
+ATCOMMAND_FUNC(kickall);
+ATCOMMAND_FUNC(allskill);
+ATCOMMAND_FUNC(questskill);
+ATCOMMAND_FUNC(charquestskill);
+ATCOMMAND_FUNC(lostskill);
+ATCOMMAND_FUNC(charlostskill);
+ATCOMMAND_FUNC(spiritball);
+ATCOMMAND_FUNC(party);
+ATCOMMAND_FUNC(guild);
+ATCOMMAND_FUNC(charskreset);
+ATCOMMAND_FUNC(charstreset);
+ATCOMMAND_FUNC(charreset);
+ATCOMMAND_FUNC(charstpoint);
+ATCOMMAND_FUNC(charmodel);
+ATCOMMAND_FUNC(charskpoint);
+ATCOMMAND_FUNC(charzeny);
+ATCOMMAND_FUNC(agitstart);
+ATCOMMAND_FUNC(agitend);
+ATCOMMAND_FUNC(reloaditemdb);
+ATCOMMAND_FUNC(reloadmobdb);
+ATCOMMAND_FUNC(reloadskilldb);
+#ifndef TXT_ONLY
+ATCOMMAND_FUNC(rehash);// by Fr3DBr
+#else /* TXT_ONLY */
+ATCOMMAND_FUNC(reloadscript);
+#endif /* TXT_ONLY */
+ATCOMMAND_FUNC(reloadgmdb); // by Yor
+ATCOMMAND_FUNC(mapexit);
+ATCOMMAND_FUNC(idsearch);
+ATCOMMAND_FUNC(mapinfo);
+ATCOMMAND_FUNC(dye); //** by fritz
+ATCOMMAND_FUNC(hair_style); //** by fritz
+ATCOMMAND_FUNC(hair_color); //** by fritz
+ATCOMMAND_FUNC(stat_all); //** by fritz
+ATCOMMAND_FUNC(char_change_sex); // by Yor
+ATCOMMAND_FUNC(char_block); // by Yor
+ATCOMMAND_FUNC(char_ban); // by Yor
+ATCOMMAND_FUNC(char_unblock); // by Yor
+ATCOMMAND_FUNC(char_unban); // by Yor
+ATCOMMAND_FUNC(mount_peco); // by Valaris
+ATCOMMAND_FUNC(char_mount_peco); // by Yor
+ATCOMMAND_FUNC(guildspy); // [Syrus22]
+ATCOMMAND_FUNC(partyspy); // [Syrus22]
+ATCOMMAND_FUNC(repairall); // [Valaris]
+ATCOMMAND_FUNC(guildrecall); // by Yor
+ATCOMMAND_FUNC(partyrecall); // by Yor
+//ATCOMMAND_FUNC(nuke); // [Valaris]
+ATCOMMAND_FUNC(enablenpc);
+ATCOMMAND_FUNC(disablenpc);
+ATCOMMAND_FUNC(servertime); // by Yor
+ATCOMMAND_FUNC(chardelitem); // by Yor
+ATCOMMAND_FUNC(jail); // by Yor
+ATCOMMAND_FUNC(unjail); // by Yor
+ATCOMMAND_FUNC(disguise); // [Valaris]
+ATCOMMAND_FUNC(undisguise); // by Yor
+ATCOMMAND_FUNC(chardisguise); // Kalaspuff
+ATCOMMAND_FUNC(charundisguise); // Kalaspuff
+ATCOMMAND_FUNC(email); // by Yor
+ATCOMMAND_FUNC(effect);//by Apple
+ATCOMMAND_FUNC(character_item_list); // by Yor
+ATCOMMAND_FUNC(character_storage_list); // by Yor
+ATCOMMAND_FUNC(character_cart_list); // by Yor
+ATCOMMAND_FUNC(addwarp); // by MouseJstr
+ATCOMMAND_FUNC(follow); // by MouseJstr
+ATCOMMAND_FUNC(skillon); // by MouseJstr
+ATCOMMAND_FUNC(skilloff); // by MouseJstr
+ATCOMMAND_FUNC(killer); // by MouseJstr
+ATCOMMAND_FUNC(npcmove); // by MouseJstr
+ATCOMMAND_FUNC(killable); // by MouseJstr
+ATCOMMAND_FUNC(charkillable); // by MouseJstr
+ATCOMMAND_FUNC(chareffect); // by MouseJstr
+ATCOMMAND_FUNC(chardye); // by MouseJstr
+ATCOMMAND_FUNC(charhairstyle); // by MouseJstr
+ATCOMMAND_FUNC(charhaircolor); // by MouseJstr
+ATCOMMAND_FUNC(dropall); // by MouseJstr
+ATCOMMAND_FUNC(chardropall); // by MouseJstr
+ATCOMMAND_FUNC(storeall); // by MouseJstr
+ATCOMMAND_FUNC(charstoreall); // by MouseJstr
+ATCOMMAND_FUNC(skillid); // by MouseJstr
+ATCOMMAND_FUNC(useskill); // by MouseJstr
+ATCOMMAND_FUNC(summon);
+ATCOMMAND_FUNC(rain);
+ATCOMMAND_FUNC(snow);
+ATCOMMAND_FUNC(sakura);
+ATCOMMAND_FUNC(fog);
+ATCOMMAND_FUNC(leaves);
+ATCOMMAND_FUNC(adjgmlvl); // by MouseJstr
+ATCOMMAND_FUNC(adjcmdlvl); // by MouseJstr
+ATCOMMAND_FUNC(trade); // by MouseJstr
+ATCOMMAND_FUNC(send); // by davidsiaw
+ATCOMMAND_FUNC(setbattleflag); // by MouseJstr
+ATCOMMAND_FUNC(unmute); // [Valaris]
+ATCOMMAND_FUNC(uptime); // by MC Cameri
+
+#ifndef TXT_ONLY
+ATCOMMAND_FUNC(checkmail); // [Valaris]
+ATCOMMAND_FUNC(listmail); // [Valaris]
+ATCOMMAND_FUNC(listnewmail); // [Valaris]
+ATCOMMAND_FUNC(readmail); // [Valaris]
+ATCOMMAND_FUNC(sendmail); // [Valaris]
+ATCOMMAND_FUNC(sendprioritymail); // [Valaris]
+ATCOMMAND_FUNC(deletemail); // [Valaris]
+ATCOMMAND_FUNC(sound); // [Valaris]
+ATCOMMAND_FUNC(refreshonline); // [Valaris]
+#endif /* TXT_ONLY */
+
+/*==========================================
+ *AtCommandInfo atcommand_info[]構造体の定義
+ *------------------------------------------
+ */
+
+// First char of commands is configured in atcommand_athena.conf. Leave @ in this list for default value.
+// to set default level, read atcommand_athena.conf first please.
+static AtCommandInfo atcommand_info[] = {
+ { AtCommand_RuraP, "@rura+", 60, atcommand_rurap },
+ { AtCommand_RuraP, "@charwarp", 60, atcommand_rurap },
+ { AtCommand_Rura, "@rura", 40, atcommand_rura },
+ { AtCommand_Warp, "@warp", 40, atcommand_rura },
+ { AtCommand_Where, "@where", 1, atcommand_where },
+ { AtCommand_JumpTo, "@jumpto", 20, atcommand_jumpto }, // + /shift
+ { AtCommand_JumpTo, "@warpto", 20, atcommand_jumpto },
+ { AtCommand_JumpTo, "@goto", 20, atcommand_jumpto },
+ { AtCommand_Jump, "@jump", 40, atcommand_jump },
+ { AtCommand_Who, "@who", 20, atcommand_who },
+ { AtCommand_Who, "@whois", 20, atcommand_who },
+ { AtCommand_Who2, "@who2", 20, atcommand_who2 },
+ { AtCommand_Who3, "@who3", 20, atcommand_who3 },
+ { AtCommand_WhoMap, "@whomap", 20, atcommand_whomap },
+ { AtCommand_WhoMap2, "@whomap2", 20, atcommand_whomap2 },
+ { AtCommand_WhoMap3, "@whomap3", 20, atcommand_whomap3 },
+ { AtCommand_WhoGM, "@whogm", 20, atcommand_whogm }, // by Yor
+ { AtCommand_Save, "@save", 40, atcommand_save },
+ { AtCommand_Load, "@return", 40, atcommand_load },
+ { AtCommand_Load, "@load", 40, atcommand_load },
+ { AtCommand_Speed, "@speed", 40, atcommand_speed },
+ { AtCommand_Storage, "@storage", 1, atcommand_storage },
+ { AtCommand_GuildStorage, "@gstorage", 50, atcommand_guildstorage },
+ { AtCommand_Option, "@option", 40, atcommand_option },
+ { AtCommand_Hide, "@hide", 40, atcommand_hide }, // + /hide
+ { AtCommand_JobChange, "@jobchange", 40, atcommand_jobchange },
+ { AtCommand_JobChange, "@job", 40, atcommand_jobchange },
+ { AtCommand_Die, "@die", 1, atcommand_die },
+ { AtCommand_Kill, "@kill", 60, atcommand_kill },
+ { AtCommand_Alive, "@alive", 60, atcommand_alive },
+ { AtCommand_Kami, "@kami", 40, atcommand_kami },
+ { AtCommand_KamiB, "@kamib", 40, atcommand_kami },
+ { AtCommand_Heal, "@heal", 40, atcommand_heal },
+ { AtCommand_Item, "@item", 60, atcommand_item },
+ { AtCommand_Item2, "@item2", 60, atcommand_item2 },
+ { AtCommand_ItemReset, "@itemreset", 40, atcommand_itemreset },
+ { AtCommand_ItemCheck, "@itemcheck", 60, atcommand_itemcheck },
+ { AtCommand_BaseLevelUp, "@lvup", 60, atcommand_baselevelup },
+ { AtCommand_BaseLevelUp, "@blevel", 60, atcommand_baselevelup },
+ { AtCommand_BaseLevelUp, "@baselvlup", 60, atcommand_baselevelup },
+ { AtCommand_JobLevelUp, "@jlevel", 60, atcommand_joblevelup },
+ { AtCommand_JobLevelUp, "@joblvup", 60, atcommand_joblevelup },
+ { AtCommand_JobLevelUp, "@joblvlup", 60, atcommand_joblevelup },
+ { AtCommand_H, "@h", 20, atcommand_help },
+ { AtCommand_Help, "@help", 20, atcommand_help },
+ { AtCommand_GM, "@gm", 100, atcommand_gm },
+ { AtCommand_PvPOff, "@pvpoff", 40, atcommand_pvpoff },
+ { AtCommand_PvPOn, "@pvpon", 40, atcommand_pvpon },
+ { AtCommand_GvGOff, "@gvgoff", 40, atcommand_gvgoff },
+ { AtCommand_GvGOff, "@gpvpoff", 40, atcommand_gvgoff },
+ { AtCommand_GvGOn, "@gvgon", 40, atcommand_gvgon },
+ { AtCommand_GvGOn, "@gpvpon", 40, atcommand_gvgon },
+ { AtCommand_Model, "@model", 20, atcommand_model },
+ { AtCommand_Go, "@go", 10, atcommand_go },
+ { AtCommand_Spawn, "@monster", 50, atcommand_spawn },
+ { AtCommand_Spawn, "@spawn", 50, atcommand_spawn },
+// { AtCommand_Spawn, "@summon", 50, atcommand_spawn },
+ { AtCommand_Monster, "@monster2", 50, atcommand_monster },
+ { AtCommand_KillMonster, "@killmonster", 60, atcommand_killmonster },
+ { AtCommand_KillMonster2, "@killmonster2", 40, atcommand_killmonster2 },
+ { AtCommand_Refine, "@refine", 60, atcommand_refine },
+ { AtCommand_Produce, "@produce", 60, atcommand_produce },
+ { AtCommand_Memo, "@memo", 40, atcommand_memo },
+ { AtCommand_GAT, "@gat", 99, atcommand_gat }, // debug function
+ { AtCommand_Packet, "@packet", 99, atcommand_packet }, // debug function
+ { AtCommand_StatusPoint, "@stpoint", 60, atcommand_statuspoint },
+ { AtCommand_SkillPoint, "@skpoint", 60, atcommand_skillpoint },
+ { AtCommand_Zeny, "@zeny", 60, atcommand_zeny },
+ { AtCommand_Strength, "@str", 60, atcommand_param },
+ { AtCommand_Agility, "@agi", 60, atcommand_param },
+ { AtCommand_Vitality, "@vit", 60, atcommand_param },
+ { AtCommand_Intelligence, "@int", 60, atcommand_param },
+ { AtCommand_Dexterity, "@dex", 60, atcommand_param },
+ { AtCommand_Luck, "@luk", 60, atcommand_param },
+ { AtCommand_GuildLevelUp, "@guildlvup", 60, atcommand_guildlevelup },
+ { AtCommand_GuildLevelUp, "@guildlvlup", 60, atcommand_guildlevelup },
+ { AtCommand_MakeEgg, "@makeegg", 60, atcommand_makeegg },
+ { AtCommand_Hatch, "@hatch", 60, atcommand_hatch },
+ { AtCommand_PetFriendly, "@petfriendly", 40, atcommand_petfriendly },
+ { AtCommand_PetHungry, "@pethungry", 40, atcommand_pethungry },
+ { AtCommand_PetRename, "@petrename", 1, atcommand_petrename },
+ { AtCommand_CharPetRename, "@charpetrename", 50, atcommand_charpetrename }, // by Yor
+ { AtCommand_Recall, "@recall", 60, atcommand_recall }, // + /recall
+ { AtCommand_CharacterJob, "@charjob", 60, atcommand_character_job },
+ { AtCommand_CharacterJob, "@charjobchange", 60, atcommand_character_job },
+ { AtCommand_Revive, "@revive", 60, atcommand_revive },
+ { AtCommand_CharacterStats, "@charstats", 40, atcommand_character_stats },
+ { AtCommand_CharacterStatsAll, "@charstatsall", 40, atcommand_character_stats_all },
+ { AtCommand_CharacterOption, "@charoption", 60, atcommand_character_option },
+ { AtCommand_CharacterSave, "@charsave", 60, atcommand_character_save },
+ { AtCommand_Night, "@night", 80, atcommand_night },
+ { AtCommand_Day, "@day", 80, atcommand_day },
+ { AtCommand_Doom, "@doom", 80, atcommand_doom },
+ { AtCommand_DoomMap, "@doommap", 80, atcommand_doommap },
+ { AtCommand_Raise, "@raise", 80, atcommand_raise },
+ { AtCommand_RaiseMap, "@raisemap", 80, atcommand_raisemap },
+ { AtCommand_CharacterBaseLevel, "@charbaselvl", 60, atcommand_character_baselevel },
+ { AtCommand_CharacterJobLevel, "@charjlvl", 60, atcommand_character_joblevel },
+ { AtCommand_Kick, "@kick", 20, atcommand_kick }, // + right click menu for GM "(name) force to quit"
+ { AtCommand_KickAll, "@kickall", 99, atcommand_kickall },
+ { AtCommand_AllSkill, "@allskill", 60, atcommand_allskill },
+ { AtCommand_AllSkill, "@allskills", 60, atcommand_allskill },
+ { AtCommand_AllSkill, "@skillall", 60, atcommand_allskill },
+ { AtCommand_AllSkill, "@skillsall", 60, atcommand_allskill },
+ { AtCommand_QuestSkill, "@questskill", 40, atcommand_questskill },
+ { AtCommand_CharQuestSkill, "@charquestskill", 60, atcommand_charquestskill },
+ { AtCommand_LostSkill, "@lostskill", 40, atcommand_lostskill },
+ { AtCommand_CharLostSkill, "@charlostskill", 60, atcommand_charlostskill },
+ { AtCommand_SpiritBall, "@spiritball", 40, atcommand_spiritball },
+ { AtCommand_Party, "@party", 1, atcommand_party },
+ { AtCommand_Guild, "@guild", 50, atcommand_guild },
+ { AtCommand_AgitStart, "@agitstart", 60, atcommand_agitstart },
+ { AtCommand_AgitEnd, "@agitend", 60, atcommand_agitend },
+ { AtCommand_MapExit, "@mapexit", 99, atcommand_mapexit },
+ { AtCommand_IDSearch, "@idsearch", 60, atcommand_idsearch },
+ { AtCommand_MapMove, "@mapmove", 40, atcommand_rura }, // /mm command
+ { AtCommand_Broadcast, "@broadcast", 40, atcommand_broadcast }, // /b and /nb command
+ { AtCommand_LocalBroadcast, "@localbroadcast", 40, atcommand_localbroadcast }, // /lb and /nlb command
+ { AtCommand_RecallAll, "@recallall", 80, atcommand_recallall },
+ { AtCommand_CharSkReset, "@charskreset", 60, atcommand_charskreset },
+ { AtCommand_CharStReset, "@charstreset", 60, atcommand_charstreset },
+ { AtCommand_ReloadItemDB, "@reloaditemdb", 99, atcommand_reloaditemdb }, // admin command
+ { AtCommand_ReloadMobDB, "@reloadmobdb", 99, atcommand_reloadmobdb }, // admin command
+ { AtCommand_ReloadSkillDB, "@reloadskilldb", 99, atcommand_reloadskilldb }, // admin command
+#ifndef TXT_ONLY
+ { AtCommand_Rehash, "@rehash", 99, atcommand_rehash }, // admin command
+#else /* TXT_ONLY */
+ { AtCommand_ReloadScript, "@reloadscript", 99, atcommand_reloadscript }, // admin command
+#endif /* TXT_ONLY */
+ { AtCommand_ReloadGMDB, "@reloadgmdb", 99, atcommand_reloadgmdb }, // admin command
+ { AtCommand_CharReset, "@charreset", 60, atcommand_charreset },
+ { AtCommand_CharModel, "@charmodel", 50, atcommand_charmodel },
+ { AtCommand_CharSKPoint, "@charskpoint", 60, atcommand_charskpoint },
+ { AtCommand_CharSTPoint, "@charstpoint", 60, atcommand_charstpoint },
+ { AtCommand_CharZeny, "@charzeny", 60, atcommand_charzeny },
+ { AtCommand_MapInfo, "@mapinfo", 99, atcommand_mapinfo },
+ { AtCommand_Dye, "@dye", 40, atcommand_dye }, // by fritz
+ { AtCommand_Dye, "@ccolor", 40, atcommand_dye }, // by fritz
+ { AtCommand_Hstyle, "@hairstyle", 40, atcommand_hair_style }, // by fritz
+ { AtCommand_Hstyle, "@hstyle", 40, atcommand_hair_style }, // by fritz
+ { AtCommand_Hcolor, "@haircolor", 40, atcommand_hair_color }, // by fritz
+ { AtCommand_Hcolor, "@hcolor", 40, atcommand_hair_color }, // by fritz
+ { AtCommand_StatAll, "@statall", 60, atcommand_stat_all }, // by fritz
+ { AtCommand_StatAll, "@statsall", 60, atcommand_stat_all },
+ { AtCommand_StatAll, "@allstats", 60, atcommand_stat_all }, // by fritz
+ { AtCommand_StatAll, "@allstat", 60, atcommand_stat_all }, // by fritz
+ { AtCommand_CharChangeSex, "@charchangesex", 60, atcommand_char_change_sex }, // by Yor
+ { AtCommand_CharBlock, "@block", 60, atcommand_char_block }, // by Yor
+ { AtCommand_CharBlock, "@charblock", 60, atcommand_char_block }, // by Yor
+ { AtCommand_CharBan, "@ban", 60, atcommand_char_ban }, // by Yor
+ { AtCommand_CharBan, "@banish", 60, atcommand_char_ban }, // by Yor
+ { AtCommand_CharBan, "@charban", 60, atcommand_char_ban }, // by Yor
+ { AtCommand_CharBan, "@charbanish", 60, atcommand_char_ban }, // by Yor
+ { AtCommand_CharUnBlock, "@unblock", 60, atcommand_char_unblock }, // by Yor
+ { AtCommand_CharUnBlock, "@charunblock", 60, atcommand_char_unblock }, // by Yor
+ { AtCommand_CharUnBan, "@unban", 60, atcommand_char_unban }, // by Yor
+ { AtCommand_CharUnBan, "@unbanish", 60, atcommand_char_unban }, // by Yor
+ { AtCommand_CharUnBan, "@charunban", 60, atcommand_char_unban }, // by Yor
+ { AtCommand_CharUnBan, "@charunbanish", 60, atcommand_char_unban }, // by Yor
+ { AtCommand_MountPeco, "@mountpeco", 20, atcommand_mount_peco }, // by Valaris
+ { AtCommand_CharMountPeco, "@charmountpeco", 50, atcommand_char_mount_peco }, // by Yor
+ { AtCommand_GuildSpy, "@guildspy", 60, atcommand_guildspy }, // [Syrus22]
+ { AtCommand_PartySpy, "@partyspy", 60, atcommand_partyspy }, // [Syrus22]
+ { AtCommand_RepairAll, "@repairall", 60, atcommand_repairall }, // [Valaris]
+ { AtCommand_GuildRecall, "@guildrecall", 60, atcommand_guildrecall }, // by Yor
+ { AtCommand_PartyRecall, "@partyrecall", 60, atcommand_partyrecall }, // by Yor
+// { AtCommand_Nuke, "@nuke", 60, atcommand_nuke }, // [Valaris]
+ { AtCommand_Enablenpc, "@enablenpc", 80, atcommand_enablenpc }, // []
+ { AtCommand_Disablenpc, "@disablenpc", 80, atcommand_disablenpc }, // []
+ { AtCommand_ServerTime, "@time", 0, atcommand_servertime }, // by Yor
+ { AtCommand_ServerTime, "@date", 0, atcommand_servertime }, // by Yor
+ { AtCommand_ServerTime, "@server_date", 0, atcommand_servertime }, // by Yor
+ { AtCommand_ServerTime, "@serverdate", 0, atcommand_servertime }, // by Yor
+ { AtCommand_ServerTime, "@server_time", 0, atcommand_servertime }, // by Yor
+ { AtCommand_ServerTime, "@servertime", 0, atcommand_servertime }, // by Yor
+ { AtCommand_CharDelItem, "@chardelitem", 60, atcommand_chardelitem }, // by Yor
+ { AtCommand_Jail, "@jail", 60, atcommand_jail }, // by Yor
+ { AtCommand_UnJail, "@unjail", 60, atcommand_unjail }, // by Yor
+ { AtCommand_UnJail, "@discharge", 60, atcommand_unjail }, // by Yor
+ { AtCommand_Disguise, "@disguise", 20, atcommand_disguise }, // [Valaris]
+ { AtCommand_UnDisguise, "@undisguise", 20, atcommand_undisguise }, // by Yor
+ { AtCommand_CharDisguise, "@chardisguise", 60, atcommand_chardisguise }, // Kalaspuff
+ { AtCommand_CharUnDisguise, "@charundisguise", 60, atcommand_charundisguise }, // Kalaspuff
+ { AtCommand_EMail, "@email", 0, atcommand_email }, // by Yor
+ { AtCommand_Effect, "@effect", 40, atcommand_effect }, // by Apple
+ { AtCommand_Char_Item_List, "@charitemlist", 40, atcommand_character_item_list }, // by Yor
+ { AtCommand_Char_Storage_List, "@charstoragelist", 40, atcommand_character_storage_list }, // by Yor
+ { AtCommand_Char_Cart_List, "@charcartlist", 40, atcommand_character_cart_list }, // by Yor
+ { AtCommand_Follow, "@follow", 10, atcommand_follow }, // by MouseJstr
+ { AtCommand_AddWarp, "@addwarp", 20, atcommand_addwarp }, // by MouseJstr
+ { AtCommand_SkillOn, "@skillon", 20, atcommand_skillon }, // by MouseJstr
+ { AtCommand_SkillOff, "@skilloff", 20, atcommand_skilloff }, // by MouseJstr
+ { AtCommand_Killer, "@killer", 60, atcommand_killer }, // by MouseJstr
+ { AtCommand_NpcMove, "@npcmove", 20, atcommand_npcmove }, // by MouseJstr
+ { AtCommand_Killable, "@killable", 40, atcommand_killable }, // by MouseJstr
+ { AtCommand_CharKillable, "@charkillable", 40, atcommand_charkillable }, // by MouseJstr
+ { AtCommand_Chareffect, "@chareffect", 40, atcommand_chareffect }, // MouseJstr
+/*
+ { AtCommand_Chardye, "@chardye", 40, atcommand_chardye }, // MouseJstr
+ { AtCommand_Charhairstyle, "@charhairstyle", 40, atcommand_charhairstyle }, // MouseJstr
+ { AtCommand_Charhaircolor, "@charhaircolor", 40, atcommand_charhaircolor }, // MouseJstr
+*/
+ { AtCommand_Dropall, "@dropall", 40, atcommand_dropall }, // MouseJstr
+ { AtCommand_Chardropall, "@chardropall", 40, atcommand_chardropall }, // MouseJstr
+ { AtCommand_Storeall, "@storeall", 40, atcommand_storeall }, // MouseJstr
+ { AtCommand_Charstoreall, "@charstoreall", 40, atcommand_charstoreall }, // MouseJstr
+ { AtCommand_Skillid, "@skillid", 40, atcommand_skillid }, // MouseJstr
+ { AtCommand_Useskill, "@useskill", 40, atcommand_useskill }, // MouseJstr
+ { AtCommand_Rain, "@rain", 99, atcommand_rain },
+ { AtCommand_Snow, "@snow", 99, atcommand_snow },
+ { AtCommand_Sakura, "@sakura", 99, atcommand_sakura },
+ { AtCommand_Fog, "@fog", 99, atcommand_fog },
+ { AtCommand_Leaves, "@leaves", 99, atcommand_leaves },
+/*
+ { AtCommand_Shuffle, "@shuffle", 99, atcommand_shuffle },
+ { AtCommand_Maintenance, "@maintenance", 99, atcommand_maintenance },
+ { AtCommand_Misceffect, "@misceffect", 60, atcommand_misceffect },
+*/
+ { AtCommand_Summon, "@summon", 60, atcommand_summon },
+ { AtCommand_AdjGmLvl, "@adjgmlvl", 99, atcommand_adjgmlvl },
+ { AtCommand_AdjCmdLvl, "@adjcmdlvl", 99, atcommand_adjcmdlvl },
+ { AtCommand_Trade, "@trade", 60, atcommand_trade },
+ { AtCommand_Send, "@send", 60, atcommand_send },
+ { AtCommand_SetBattleFlag, "@setbattleflag", 60, atcommand_setbattleflag },
+ { AtCommand_UnMute, "@unmute", 60, atcommand_unmute }, // [Valaris]
+ { AtCommand_UpTime, "@uptime", 0, atcommand_uptime }, // by MC Cameri
+
+#ifndef TXT_ONLY // sql-only commands
+ { AtCommand_CheckMail, "@checkmail", 1, atcommand_listmail }, // [Valaris]
+ { AtCommand_ListMail, "@listmail", 1, atcommand_listmail }, // [Valaris]
+ { AtCommand_ListNewMail, "@listnewmail", 1, atcommand_listmail }, // [Valaris]
+ { AtCommand_ReadMail, "@readmail", 1, atcommand_readmail }, // [Valaris]
+ { AtCommand_DeleteMail, "@deletemail", 1, atcommand_readmail }, // [Valaris]
+ { AtCommand_SendMail, "@sendmail", 1, atcommand_sendmail }, // [Valaris]
+ { AtCommand_SendPriorityMail, "@sendprioritymail",80, atcommand_sendmail }, // [Valaris]
+ { AtCommand_RefreshOnline, "@refreshonline", 99, atcommand_refreshonline }, // [Valaris]
+#endif /* TXT_ONLY */
+
+// add new commands before this line
+ { AtCommand_Unknown, NULL, 1, NULL }
+};
+
+/*====================================================
+ * This function return the name of the job (by [Yor])
+ *----------------------------------------------------
+ */
+char * job_name(int class) {
+ switch (class) {
+ case 0: return "Novice";
+ case 1: return "Swordsman";
+ case 2: return "Mage";
+ case 3: return "Archer";
+ case 4: return "Acolyte";
+ case 5: return "Merchant";
+ case 6: return "Thief";
+ case 7: return "Knight";
+ case 8: return "Priest";
+ case 9: return "Wizard";
+ case 10: return "Blacksmith";
+ case 11: return "Hunter";
+ case 12: return "Assassin";
+ case 13: return "Knight 2";
+ case 14: return "Crusader";
+ case 15: return "Monk";
+ case 16: return "Sage";
+ case 17: return "Rogue";
+ case 18: return "Alchemist";
+ case 19: return "Bard";
+ case 20: return "Dancer";
+ case 21: return "Crusader 2";
+ case 22: return "Wedding";
+ case 23: return "Super Novice";
+ case 4001: return "Novice High";
+ case 4002: return "Swordsman High";
+ case 4003: return "Mage High";
+ case 4004: return "Archer High";
+ case 4005: return "Acolyte High";
+ case 4006: return "Merchant High";
+ case 4007: return "Thief High";
+ case 4008: return "Lord Knight";
+ case 4009: return "High Priest";
+ case 4010: return "High Wizard";
+ case 4011: return "Whitesmith";
+ case 4012: return "Sniper";
+ case 4013: return "Assassin Cross";
+ case 4014: return "Peko Knight";
+ case 4015: return "Paladin";
+ case 4016: return "Champion";
+ case 4017: return "Professor";
+ case 4018: return "Stalker";
+ case 4019: return "Creator";
+ case 4020: return "Clown";
+ case 4021: return "Gypsy";
+ case 4022: return "Peko Paladin";
+ case 4023: return "Baby Novice";
+ case 4024: return "Baby Swordsman";
+ case 4025: return "Baby Mage";
+ case 4026: return "Baby Archer";
+ case 4027: return "Baby Acolyte";
+ case 4028: return "Baby Merchant";
+ case 4029: return "Baby Thief";
+ case 4030: return "Baby Knight";
+ case 4031: return "Baby Priest";
+ case 4032: return "Baby Wizard";
+ case 4033: return "Baby Blacksmith";
+ case 4034: return "Baby Hunter";
+ case 4035: return "Baby Assassin";
+ case 4036: return "Baby Peco Knight";
+ case 4037: return "Baby Crusader";
+ case 4038: return "Baby Monk";
+ case 4039: return "Baby Sage";
+ case 4040: return "Baby Rogue";
+ case 4041: return "Baby Alchemist";
+ case 4042: return "Baby Bard";
+ case 4043: return "Baby Dancer";
+ case 4044: return "Baby Peco Crusader";
+ case 4045: return "Super Baby";
+ }
+ return "Unknown Job";
+}
+
+//-----------------------------------------------------------
+// Return the message string of the specified number by [Yor]
+//-----------------------------------------------------------
+char * msg_txt(int msg_number) {
+ if (msg_number >= 0 && msg_number < (int)(sizeof(msg_table) / sizeof(msg_table[0])) &&
+ msg_table[msg_number] != NULL && msg_table[msg_number][0] != '\0')
+ return msg_table[msg_number];
+
+ return "??";
+}
+
+//------------------------------------------------------------
+// E-mail check: return 0 (not correct) or 1 (valid). by [Yor]
+//------------------------------------------------------------
+int e_mail_check(unsigned char *email) {
+ char ch;
+ unsigned char* last_arobas;
+
+ // athena limits
+ if (strlen(email) < 3 || strlen(email) > 39)
+ return 0;
+
+ // part of RFC limits (official reference of e-mail description)
+ if (strchr(email, '@') == NULL || email[strlen(email)-1] == '@')
+ return 0;
+
+ if (email[strlen(email)-1] == '.')
+ return 0;
+
+ last_arobas = strrchr(email, '@');
+
+ if (strstr(last_arobas, "@.") != NULL ||
+ strstr(last_arobas, "..") != NULL)
+ return 0;
+
+ for(ch = 1; ch < 32; ch++) {
+ if (strchr(last_arobas, ch) != NULL) {
+ return 0;
+ break;
+ }
+ }
+
+ if (strchr(last_arobas, ' ') != NULL ||
+ strchr(last_arobas, ';') != NULL)
+ return 0;
+
+ // all correct
+ return 1;
+}
+
+/*==========================================
+ * get_atcommand_level @コマンドの必要レベルを取得
+ *------------------------------------------
+ */
+int get_atcommand_level(const AtCommandType type) {
+ int i;
+
+ for (i = 0; atcommand_info[i].type != AtCommand_None; i++)
+ if (atcommand_info[i].type == type)
+ return atcommand_info[i].level;
+
+ return 100; // 100: command can not be used
+}
+
+/*==========================================
+ *is_atcommand @コマンドに存在するかどうか確認する
+ *------------------------------------------
+ */
+AtCommandType
+is_atcommand(const int fd, struct map_session_data* sd, const char* message, int gmlvl) {
+ const char* str = message;
+ int s_flag = 0;
+ AtCommandInfo info;
+ AtCommandType type;
+
+ nullpo_retr(AtCommand_None, sd);
+
+ if (!message || !*message)
+ return AtCommand_None;
+
+ memset(&info, 0, sizeof(info));
+ str += strlen(sd->status.name);
+ while (*str && (isspace(*str) || (s_flag == 0 && *str == ':'))) {
+ if (*str == ':')
+ s_flag = 1;
+ str++;
+ }
+ if (!*str)
+ return AtCommand_None;
+
+ type = atcommand(gmlvl > 0 ? gmlvl : pc_isGM(sd), str, &info);
+ if (type != AtCommand_None) {
+ char command[100];
+ char output[200];
+ const char* p = str;
+ memset(command, '\0', sizeof(command));
+ memset(output, '\0', sizeof(output));
+ while (*p && !isspace(*p))
+ p++;
+ if (p - str >= sizeof(command)) // too long
+ return AtCommand_Unknown;
+ strncpy(command, str, p - str);
+ while (isspace(*p))
+ p++;
+
+ if (type == AtCommand_Unknown || info.proc == NULL) {
+ sprintf(output, msg_table[153], command); // %s is Unknown Command.
+ clif_displaymessage(fd, output);
+ } else {
+ if (info.proc(fd, sd, command, p) != 0) {
+ // Command can not be executed
+ sprintf(output, msg_table[154], command); // %s failed.
+ clif_displaymessage(fd, output);
+ }
+ }
+
+ return info.type;
+ }
+
+ return AtCommand_None;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+AtCommandType atcommand(const int level, const char* message, struct AtCommandInfo* info) {
+ char* p = (char *)message; // it's 'char' and not 'const char' to have possibility to modify the first character if necessary
+
+ if (!info)
+ return AtCommand_None;
+ if (battle_config.atc_gmonly != 0 && !level) // level = pc_isGM(sd)
+ return AtCommand_None;
+ if (!p || !*p) {
+ fprintf(stderr, "at command message is empty\n");
+ return AtCommand_None;
+ }
+
+ if (*p == command_symbol) { // check first char.
+ char command[101];
+ int i = 0;
+ memset(info, 0, sizeof(AtCommandInfo));
+ sscanf(p, "%100s", command);
+ command[sizeof(command)-1] = '\0';
+
+ while (atcommand_info[i].type != AtCommand_Unknown) {
+ if (strcmpi(command+1, atcommand_info[i].command+1) == 0 && level >= atcommand_info[i].level) {
+ p[0] = atcommand_info[i].command[0]; // set correct first symbol for after.
+ break;
+ }
+ i++;
+ }
+
+ if (atcommand_info[i].type == AtCommand_Unknown) {
+ // doesn't return Unknown if player is normal player (display the text, not display: unknown command)
+ if (level == 0)
+ return AtCommand_None;
+ else
+ return AtCommand_Unknown;
+ }
+ memcpy(info, &atcommand_info[i], sizeof atcommand_info[i]);
+ } else {
+ return AtCommand_None;
+ }
+
+ return info->type;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static int atkillmonster_sub(struct block_list *bl, va_list ap) {
+ int flag = va_arg(ap, int);
+
+ nullpo_retr(0, bl);
+
+ if (flag)
+ mob_damage(NULL, (struct mob_data *)bl, ((struct mob_data *)bl)->hp, 2);
+ else
+ mob_delete((struct mob_data *)bl);
+
+ return 0;
+}
+
+#ifndef TXT_ONLY
+static int atkillnpc_sub(struct block_list *bl, va_list ap)
+{
+ int flag = va_arg(ap,int);
+
+ nullpo_retr(0, bl);
+
+ npc_delete((struct npc_data *)bl);
+
+ flag = 0;
+
+ return 0;
+}
+
+void rehash( const int fd, struct map_session_data* sd )
+{
+ int map_id = 0;
+
+ int LOADED_MAPS = map_num;
+
+ for (map_id = 0; map_id < LOADED_MAPS;map_id++) {
+
+ if (map_id > LOADED_MAPS)
+ break;
+
+ map_foreachinarea(atkillmonster_sub, map_id, 0, 0, map[map_id].xs, map[map_id].ys, BL_MOB, 0);
+ map_foreachinarea(atkillnpc_sub, map_id, 0, 0, map[map_id].xs, map[map_id].ys, BL_NPC, 0);
+ }
+}
+
+#endif /* not TXT_ONLY */
+/*==========================================
+ * Read Message Data
+ *------------------------------------------
+ */
+int msg_config_read(const char *cfgName) {
+ int msg_number;
+ char line[1024], w1[1024], w2[1024];
+ FILE *fp;
+
+ if ((fp = fopen(cfgName, "r")) == NULL) {
+ printf("Messages file not found: %s\n", cfgName);
+ return 1;
+ }
+
+ while(fgets(line, sizeof(line)-1, fp)) {
+ if (line[0] == '/' && line[1] == '/')
+ continue;
+ if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) == 2) {
+ if (strcmpi(w1, "import") == 0) {
+ msg_config_read(w2);
+ } else {
+ msg_number = atoi(w1);
+ if (msg_number >= 0 && msg_number < (int)(sizeof(msg_table) / sizeof(msg_table[0])))
+ strcpy(msg_table[msg_number], w2);
+ // printf("message #%d: '%s'.\n", msg_number, msg_table[msg_number]);
+ }
+ }
+ }
+ fclose(fp);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static AtCommandInfo* get_atcommandinfo_byname(const char* name) {
+ int i;
+
+ for (i = 0; atcommand_info[i].type != AtCommand_Unknown; i++)
+ if (strcmpi(atcommand_info[i].command + 1, name) == 0)
+ return &atcommand_info[i];
+
+ return NULL;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_config_read(const char *cfgName) {
+ char line[1024], w1[1024], w2[1024];
+ AtCommandInfo* p;
+ FILE* fp;
+
+ if ((fp = fopen(cfgName, "r")) == NULL) {
+ printf("At commands configuration file not found: %s\n", cfgName);
+ return 1;
+ }
+
+ while (fgets(line, sizeof(line)-1, fp)) {
+ if (line[0] == '/' && line[1] == '/')
+ continue;
+
+ if (sscanf(line, "%1023[^:]:%1023s", w1, w2) != 2)
+ continue;
+ p = get_atcommandinfo_byname(w1);
+ if (p != NULL) {
+ p->level = atoi(w2);
+ if (p->level > 100)
+ p->level = 100;
+ else if (p->level < 0)
+ p->level = 0;
+ }
+
+ if (strcmpi(w1, "import") == 0)
+ atcommand_config_read(w2);
+ else if (strcmpi(w1, "command_symbol") == 0 && w2[0] > 31 &&
+ w2[0] != '/' && // symbol of standard ragnarok GM commands
+ w2[0] != '%') // symbol of party chat speaking
+ command_symbol = w2[0];
+ }
+ fclose(fp);
+
+ return 0;
+}
+
+
+
+/*==========================================
+// @ command processing functions
+ *------------------------------------------
+ */
+
+/*==========================================
+ * @send (used for testing packet sends from the client)
+ *------------------------------------------
+ */
+int atcommand_send(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int a = atoi(message);
+ if (a)
+ {
+ unsigned char buf[1024];
+ switch(a)
+ {
+ case 1:
+ WBUFW(buf,0)=0x18d;
+ case 2:
+ WBUFW(buf,0)=0x18e;
+ case 3:
+ WBUFW(buf,0)=0x18f;
+ case 4:
+ WBUFW(buf,0)=0x190;
+ }
+
+
+ }
+ return 0;
+}
+
+/*==========================================
+ * @rura+
+ *------------------------------------------
+ */
+int atcommand_rurap(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char map_name[100];
+ char character[100];
+ int x = 0, y = 0;
+ struct map_session_data *pl_sd;
+ int m;
+
+ memset(map_name, '\0', sizeof(map_name));
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%99s %d %d %99[^\n]", map_name, &x, &y, character) < 4) {
+ clif_displaymessage(fd, "Usage: @charwarp/@rura+ <mapname> <x> <y> <char name>");
+ return -1;
+ }
+
+ if (x <= 0)
+ x = rand() % 399 + 1;
+ if (y <= 0)
+ y = rand() % 399 + 1;
+ if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat)
+ strcat(map_name, ".gat");
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can rura+ only lower or same GM level
+ if (x > 0 && x < 400 && y > 0 && y < 400) {
+ m = map_mapname2mapid(map_name);
+ if (m >= 0 && map[m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp someone to this map.");
+ return -1;
+ }
+ if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp this player from its actual map.");
+ return -1;
+ }
+ if (pc_setpos(pl_sd, map_name, x, y, 3) == 0) {
+ clif_displaymessage(pl_sd->fd, msg_table[0]); // Warped.
+ clif_displaymessage(fd, msg_table[15]); // Player warped (message sends to player too).
+ } else {
+ clif_displaymessage(fd, msg_table[1]); // Map not found.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[2]); // Coordinates out of range.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+// @rura
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_rura(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char map_name[100];
+ int x = 0, y = 0;
+ int m;
+
+ memset(map_name, '\0', sizeof(map_name));
+
+ if (!message || !*message || sscanf(message, "%99s %d %d", map_name, &x, &y) < 1) {
+ clif_displaymessage(fd, "Please, enter a map (usage: @warp/@rura/@mapmove <mapname> <x> <y>).");
+ return -1;
+ }
+
+ if (x <= 0)
+ x = rand() % 399 + 1;
+ if (y <= 0)
+ y = rand() % 399 + 1;
+
+ if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat)
+ strcat(map_name, ".gat");
+
+ if (x > 0 && x < 400 && y > 0 && y < 400) {
+ m = map_mapname2mapid(map_name);
+ if (m >= 0 && map[m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp you to this map.");
+ return -1;
+ }
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp you from your actual map.");
+ return -1;
+ }
+ if (pc_setpos(sd, map_name, x, y, 3) == 0)
+ clif_displaymessage(fd, msg_table[0]); // Warped.
+ else {
+ clif_displaymessage(fd, msg_table[1]); // Map not found.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[2]); // Coordinates out of range.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_where(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ char output[200];
+ struct map_session_data *pl_sd = NULL;
+
+ nullpo_retr(-1, sd);
+
+ if (!message || !*message)
+ return -1;
+ memset(character, '\0', sizeof character);
+ if (sscanf(message, "%99[^\n]", character) < 1)
+ return -1;
+ if(strncmp(sd->status.name,character,24)==0)
+ return -1;
+
+ intif_where(sd->status.account_id,character);
+
+ if ((pl_sd = map_nick2sd(character)) == NULL) {
+ snprintf(output, sizeof output, "%s %d %d",
+ sd->mapname, sd->bl.x, sd->bl.y);
+ clif_displaymessage(fd, output);
+ return -1;
+ }
+ snprintf(output, sizeof output, "%s %s %d %d",
+ character, pl_sd->mapname, pl_sd->bl.x, pl_sd->bl.y);
+ clif_displaymessage(fd, output);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_jumpto(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ char output[200];
+ struct map_session_data *pl_sd = NULL;
+
+ nullpo_retr(-1, sd);
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @jumpto/@warpto/@goto <char name>).");
+ return -1;
+ }
+
+ memset(character, '\0', sizeof character);
+ if (sscanf(message, "%99[^\n]", character) < 1)
+ return -1;
+ if(strncmp(sd->status.name,character,24)==0)
+ return -1;
+
+ intif_jumpto(sd->status.account_id,character);
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp you to the map of this player.");
+ return -1;
+ }
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp you from your actual map.");
+ return -1;
+ }
+ pc_setpos(sd, pl_sd->mapname, pl_sd->bl.x, pl_sd->bl.y, 3);
+ sprintf(output, msg_table[4], character); // Jump to %s
+ clif_displaymessage(fd, output);
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_jump(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char output[200];
+ int x = 0, y = 0;
+
+ memset(output, '\0', sizeof(output));
+
+ sscanf(message, "%d %d", &x, &y);
+
+ if (x <= 0)
+ x = rand() % 399 + 1;
+ if (y <= 0)
+ y = rand() % 399 + 1;
+ if (x > 0 && x < 400 && y > 0 && y < 400) {
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp you to your actual map.");
+ return -1;
+ }
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp you from your actual map.");
+ return -1;
+ }
+ pc_setpos(sd, sd->mapname, x, y, 3);
+ sprintf(output, msg_table[5], x, y); // Jump to %d %d
+ clif_displaymessage(fd, output);
+ } else {
+ clif_displaymessage(fd, msg_table[2]); // Coordinates out of range.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_who(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char output[200];
+ struct map_session_data *pl_sd;
+ int i, j, count;
+ int pl_GM_level, GM_level;
+ char match_text[100];
+ char player_name[24];
+
+ memset(output, '\0', sizeof(output));
+ memset(match_text, '\0', sizeof(match_text));
+ memset(player_name, '\0', sizeof(player_name));
+
+ if (sscanf(message, "%99[^\n]", match_text) < 1)
+ strcpy(match_text, "");
+ for (j = 0; match_text[j]; j++)
+ match_text[j] = tolower(match_text[j]);
+
+ count = 0;
+ GM_level = pc_isGM(sd);
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
+ pl_GM_level = pc_isGM(pl_sd);
+ if (!((battle_config.hide_GM_session || (pl_sd->status.option & OPTION_HIDE)) && (pl_GM_level > GM_level))) { // you can look only lower or same level
+ memcpy(player_name, pl_sd->status.name, 24);
+ for (j = 0; player_name[j]; j++)
+ player_name[j] = tolower(player_name[j]);
+ if (strstr(player_name, match_text) != NULL) { // search with no case sensitive
+ if (pl_GM_level > 0)
+ sprintf(output, "Name: %s (GM:%d) | Location: %s %d %d", pl_sd->status.name, pl_GM_level, pl_sd->mapname, pl_sd->bl.x, pl_sd->bl.y);
+ else
+ sprintf(output, "Name: %s | Location: %s %d %d", pl_sd->status.name, pl_sd->mapname, pl_sd->bl.x, pl_sd->bl.y);
+ clif_displaymessage(fd, output);
+ count++;
+ }
+ }
+ }
+ }
+
+ if (count == 0)
+ clif_displaymessage(fd, msg_table[28]); // No player found.
+ else if (count == 1)
+ clif_displaymessage(fd, msg_table[29]); // 1 player found.
+ else {
+ sprintf(output, msg_table[30], count); // %d players found.
+ clif_displaymessage(fd, output);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_who2(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char output[200];
+ struct map_session_data *pl_sd;
+ int i, j, count;
+ int pl_GM_level, GM_level;
+ char match_text[100];
+ char player_name[24];
+
+ memset(output, '\0', sizeof(output));
+ memset(match_text, '\0', sizeof(match_text));
+ memset(player_name, '\0', sizeof(player_name));
+
+ if (sscanf(message, "%99[^\n]", match_text) < 1)
+ strcpy(match_text, "");
+ for (j = 0; match_text[j]; j++)
+ match_text[j] = tolower(match_text[j]);
+
+ count = 0;
+ GM_level = pc_isGM(sd);
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
+ pl_GM_level = pc_isGM(pl_sd);
+ if (!((battle_config.hide_GM_session || (pl_sd->status.option & OPTION_HIDE)) && (pl_GM_level > GM_level))) { // you can look only lower or same level
+ memcpy(player_name, pl_sd->status.name, 24);
+ for (j = 0; player_name[j]; j++)
+ player_name[j] = tolower(player_name[j]);
+ if (strstr(player_name, match_text) != NULL) { // search with no case sensitive
+ if (pl_GM_level > 0)
+ sprintf(output, "Name: %s (GM:%d) | BLvl: %d | Job: %s (Lvl: %d)", pl_sd->status.name, pl_GM_level, pl_sd->status.base_level, job_name(pl_sd->status.class), pl_sd->status.job_level);
+ else
+ sprintf(output, "Name: %s | BLvl: %d | Job: %s (Lvl: %d)", pl_sd->status.name, pl_sd->status.base_level, job_name(pl_sd->status.class), pl_sd->status.job_level);
+ clif_displaymessage(fd, output);
+ count++;
+ }
+ }
+ }
+ }
+
+ if (count == 0)
+ clif_displaymessage(fd, msg_table[28]); // No player found.
+ else if (count == 1)
+ clif_displaymessage(fd, msg_table[29]); // 1 player found.
+ else {
+ sprintf(output, msg_table[30], count); // %d players found.
+ clif_displaymessage(fd, output);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_who3(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char temp0[100];
+ char temp1[100];
+ char output[200];
+ struct map_session_data *pl_sd;
+ int i, j, count;
+ int pl_GM_level, GM_level;
+ char match_text[100];
+ char player_name[24];
+ struct guild *g;
+ struct party *p;
+
+ memset(temp0, '\0', sizeof(temp0));
+ memset(temp1, '\0', sizeof(temp1));
+ memset(output, '\0', sizeof(output));
+ memset(match_text, '\0', sizeof(match_text));
+ memset(player_name, '\0', sizeof(player_name));
+
+ if (sscanf(message, "%99[^\n]", match_text) < 1)
+ strcpy(match_text, "");
+ for (j = 0; match_text[j]; j++)
+ match_text[j] = tolower(match_text[j]);
+
+ count = 0;
+ GM_level = pc_isGM(sd);
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
+ pl_GM_level = pc_isGM(pl_sd);
+ if (!((battle_config.hide_GM_session || (pl_sd->status.option & OPTION_HIDE)) && (pl_GM_level > GM_level))) { // you can look only lower or same level
+ memcpy(player_name, pl_sd->status.name, 24);
+ for (j = 0; player_name[j]; j++)
+ player_name[j] = tolower(player_name[j]);
+ if (strstr(player_name, match_text) != NULL) { // search with no case sensitive
+ g = guild_search(pl_sd->status.guild_id);
+ if (g == NULL)
+ sprintf(temp1, "None");
+ else
+ sprintf(temp1, "%s", g->name);
+ p = party_search(pl_sd->status.party_id);
+ if (p == NULL)
+ sprintf(temp0, "None");
+ else
+ sprintf(temp0, "%s", p->name);
+ if (pl_GM_level > 0)
+ sprintf(output, "Name: %s (GM:%d) | Party: '%s' | Guild: '%s'", pl_sd->status.name, pl_GM_level, temp0, temp1);
+ else
+ sprintf(output, "Name: %s | Party: '%s' | Guild: '%s'", pl_sd->status.name, temp0, temp1);
+ clif_displaymessage(fd, output);
+ count++;
+ }
+ }
+ }
+ }
+
+ if (count == 0)
+ clif_displaymessage(fd, msg_table[28]); // No player found.
+ else if (count == 1)
+ clif_displaymessage(fd, msg_table[29]); // 1 player found.
+ else {
+ sprintf(output, msg_table[30], count); // %d players found.
+ clif_displaymessage(fd, output);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_whomap(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char output[200];
+ struct map_session_data *pl_sd;
+ int i, count;
+ int pl_GM_level, GM_level;
+ int map_id;
+ char map_name[100];
+
+ memset(output, '\0', sizeof(output));
+ memset(map_name, '\0', sizeof(map_name));
+
+ if (!message || !*message)
+ map_id = sd->bl.m;
+ else {
+ sscanf(message, "%99s", map_name);
+ if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat)
+ strcat(map_name, ".gat");
+ if ((map_id = map_mapname2mapid(map_name)) < 0)
+ map_id = sd->bl.m;
+ }
+
+ count = 0;
+ GM_level = pc_isGM(sd);
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
+ pl_GM_level = pc_isGM(pl_sd);
+ if (!((battle_config.hide_GM_session || (pl_sd->status.option & OPTION_HIDE)) && (pl_GM_level > GM_level))) { // you can look only lower or same level
+ if (pl_sd->bl.m == map_id) {
+ if (pl_GM_level > 0)
+ sprintf(output, "Name: %s (GM:%d) | Location: %s %d %d", pl_sd->status.name, pl_GM_level, pl_sd->mapname, pl_sd->bl.x, pl_sd->bl.y);
+ else
+ sprintf(output, "Name: %s | Location: %s %d %d", pl_sd->status.name, pl_sd->mapname, pl_sd->bl.x, pl_sd->bl.y);
+ clif_displaymessage(fd, output);
+ count++;
+ }
+ }
+ }
+ }
+
+ if (count == 0)
+ sprintf(output, msg_table[54], map[map_id].name); // No player found in map '%s'.
+ else if (count == 1)
+ sprintf(output, msg_table[55], map[map_id].name); // 1 player found in map '%s'.
+ else {
+ sprintf(output, msg_table[56], count, map[map_id].name); // %d players found in map '%s'.
+ }
+ clif_displaymessage(fd, output);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_whomap2(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char output[200];
+ struct map_session_data *pl_sd;
+ int i, count;
+ int pl_GM_level, GM_level;
+ int map_id = 0;
+ char map_name[100];
+
+ memset(output, '\0', sizeof(output));
+ memset(map_name, '\0', sizeof(map_name));
+
+ if (!message || !*message)
+ map_id = sd->bl.m;
+ else {
+ sscanf(message, "%99s", map_name);
+ if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat)
+ strcat(map_name, ".gat");
+ if ((map_id = map_mapname2mapid(map_name)) < 0)
+ map_id = sd->bl.m;
+ }
+
+ count = 0;
+ GM_level = pc_isGM(sd);
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
+ pl_GM_level = pc_isGM(pl_sd);
+ if (!((battle_config.hide_GM_session || (pl_sd->status.option & OPTION_HIDE)) && (pl_GM_level > GM_level))) { // you can look only lower or same level
+ if (pl_sd->bl.m == map_id) {
+ if (pl_GM_level > 0)
+ sprintf(output, "Name: %s (GM:%d) | BLvl: %d | Job: %s (Lvl: %d)", pl_sd->status.name, pl_GM_level, pl_sd->status.base_level, job_name(pl_sd->status.class), pl_sd->status.job_level);
+ else
+ sprintf(output, "Name: %s | BLvl: %d | Job: %s (Lvl: %d)", pl_sd->status.name, pl_sd->status.base_level, job_name(pl_sd->status.class), pl_sd->status.job_level);
+ clif_displaymessage(fd, output);
+ count++;
+ }
+ }
+ }
+ }
+
+ if (count == 0)
+ sprintf(output, msg_table[54], map[map_id].name); // No player found in map '%s'.
+ else if (count == 1)
+ sprintf(output, msg_table[55], map[map_id].name); // 1 player found in map '%s'.
+ else {
+ sprintf(output, msg_table[56], count, map[map_id].name); // %d players found in map '%s'.
+ }
+ clif_displaymessage(fd, output);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_whomap3(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char temp0[100];
+ char temp1[100];
+ char output[200];
+ struct map_session_data *pl_sd;
+ int i, count;
+ int pl_GM_level, GM_level;
+ int map_id = 0;
+ char map_name[100];
+ struct guild *g;
+ struct party *p;
+
+ memset(temp0, '\0', sizeof(temp0));
+ memset(temp1, '\0', sizeof(temp1));
+ memset(output, '\0', sizeof(output));
+ memset(map_name, '\0', sizeof(map_name));
+
+ if (!message || !*message)
+ map_id = sd->bl.m;
+ else {
+ sscanf(message, "%99s", map_name);
+ if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat)
+ strcat(map_name, ".gat");
+ if ((map_id = map_mapname2mapid(map_name)) < 0)
+ map_id = sd->bl.m;
+ }
+
+ count = 0;
+ GM_level = pc_isGM(sd);
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
+ pl_GM_level = pc_isGM(pl_sd);
+ if (!((battle_config.hide_GM_session || (pl_sd->status.option & OPTION_HIDE)) && (pl_GM_level > GM_level))) { // you can look only lower or same level
+ if (pl_sd->bl.m == map_id) {
+ g = guild_search(pl_sd->status.guild_id);
+ if (g == NULL)
+ sprintf(temp1, "None");
+ else
+ sprintf(temp1, "%s", g->name);
+ p = party_search(pl_sd->status.party_id);
+ if (p == NULL)
+ sprintf(temp0, "None");
+ else
+ sprintf(temp0, "%s", p->name);
+ if (pl_GM_level > 0)
+ sprintf(output, "Name: %s (GM:%d) | Party: '%s' | Guild: '%s'", pl_sd->status.name, pl_GM_level, temp0, temp1);
+ else
+ sprintf(output, "Name: %s | Party: '%s' | Guild: '%s'", pl_sd->status.name, temp0, temp1);
+ clif_displaymessage(fd, output);
+ count++;
+ }
+ }
+ }
+ }
+
+ if (count == 0)
+ sprintf(output, msg_table[54], map[map_id].name); // No player found in map '%s'.
+ else if (count == 1)
+ sprintf(output, msg_table[55], map[map_id].name); // 1 player found in map '%s'.
+ else {
+ sprintf(output, msg_table[56], count, map[map_id].name); // %d players found in map '%s'.
+ }
+ clif_displaymessage(fd, output);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_whogm(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char temp0[100];
+ char temp1[100];
+ char output[200];
+ struct map_session_data *pl_sd;
+ int i, j, count;
+ int pl_GM_level, GM_level;
+ char match_text[100];
+ char player_name[24];
+ struct guild *g;
+ struct party *p;
+
+ memset(temp0, '\0', sizeof(temp0));
+ memset(temp1, '\0', sizeof(temp1));
+ memset(output, '\0', sizeof(output));
+ memset(match_text, '\0', sizeof(match_text));
+ memset(player_name, '\0', sizeof(player_name));
+
+ if (sscanf(message, "%99[^\n]", match_text) < 1)
+ strcpy(match_text, "");
+ for (j = 0; match_text[j]; j++)
+ match_text[j] = tolower(match_text[j]);
+
+ count = 0;
+ GM_level = pc_isGM(sd);
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
+ pl_GM_level = pc_isGM(pl_sd);
+ if (pl_GM_level > 0) {
+ if (!((battle_config.hide_GM_session || (pl_sd->status.option & OPTION_HIDE)) && (pl_GM_level > GM_level))) { // you can look only lower or same level
+ memcpy(player_name, pl_sd->status.name, 24);
+ for (j = 0; player_name[j]; j++)
+ player_name[j] = tolower(player_name[j]);
+ if (strstr(player_name, match_text) != NULL) { // search with no case sensitive
+ sprintf(output, "Name: %s (GM:%d) | Location: %s %d %d", pl_sd->status.name, pl_GM_level, pl_sd->mapname, pl_sd->bl.x, pl_sd->bl.y);
+ clif_displaymessage(fd, output);
+ sprintf(output, " BLvl: %d | Job: %s (Lvl: %d)", pl_sd->status.base_level, job_name(pl_sd->status.class), pl_sd->status.job_level);
+ clif_displaymessage(fd, output);
+ g = guild_search(pl_sd->status.guild_id);
+ if (g == NULL)
+ sprintf(temp1, "None");
+ else
+ sprintf(temp1, "%s", g->name);
+ p = party_search(pl_sd->status.party_id);
+ if (p == NULL)
+ sprintf(temp0, "None");
+ else
+ sprintf(temp0, "%s", p->name);
+ sprintf(output, " Party: '%s' | Guild: '%s'", temp0, temp1);
+ clif_displaymessage(fd, output);
+ count++;
+ }
+ }
+ }
+ }
+ }
+
+ if (count == 0)
+ clif_displaymessage(fd, msg_table[150]); // No GM found.
+ else if (count == 1)
+ clif_displaymessage(fd, msg_table[151]); // 1 GM found.
+ else {
+ sprintf(output, msg_table[152], count); // %d GMs found.
+ clif_displaymessage(fd, output);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_save(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ pc_setsavepoint(sd, sd->mapname, sd->bl.x, sd->bl.y);
+ if (sd->status.pet_id > 0 && sd->pd)
+ intif_save_petdata(sd->status.account_id, &sd->pet);
+ pc_makesavestatus(sd);
+ chrif_save(sd);
+ storage_storage_save(sd);
+ clif_displaymessage(fd, msg_table[6]); // Character data respawn point saved.
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_load(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int m;
+
+ m = map_mapname2mapid(sd->status.save_point.map);
+ if (m >= 0 && map[m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp you to your save map.");
+ return -1;
+ }
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp you from your actual map.");
+ return -1;
+ }
+
+ pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, 0);
+ clif_displaymessage(fd, msg_table[7]); // Warping to respawn point.
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_speed(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char output[200];
+ int speed;
+
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message) {
+ sprintf(output, "Please, enter a speed value (usage: @speed <%d-%d>).", MIN_WALK_SPEED, MAX_WALK_SPEED);
+ clif_displaymessage(fd, output);
+ return -1;
+ }
+
+ speed = atoi(message);
+ if (speed >= MIN_WALK_SPEED && speed <= MAX_WALK_SPEED) {
+ sd->speed = speed;
+ //sd->walktimer = x;
+ //この文を追加 by れ
+ clif_updatestatus(sd, SP_SPEED);
+ clif_displaymessage(fd, msg_table[8]); // Speed changed.
+ } else {
+ sprintf(output, "Please, enter a valid speed value (usage: @speed <%d-%d>).", MIN_WALK_SPEED, MAX_WALK_SPEED);
+ clif_displaymessage(fd, output);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_storage(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ storage_storageopen(sd);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_guildstorage(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ if (sd->status.guild_id > 0)
+ storage_guild_storageopen(sd);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_option(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int param1 = 0, param2 = 0, param3 = 0;
+
+ if (!message || !*message || sscanf(message, "%d %d %d", &param1, &param2, &param3) < 1 || param1 < 0 || param2 < 0 || param3 < 0) {
+ clif_displaymessage(fd, "Please, enter at least a option (usage: @option <param1:0+> <param2:0+> <param3:0+>).");
+ return -1;
+ }
+
+ sd->opt1 = param1;
+ sd->opt2 = param2;
+ if (!(sd->status.option & CART_MASK) && param3 & CART_MASK) {
+ clif_cart_itemlist(sd);
+ clif_cart_equiplist(sd);
+ clif_updatestatus(sd, SP_CARTINFO);
+ }
+ sd->status.option = param3;
+ // fix pecopeco display
+ if (sd->status.class == 13 || sd->status.class == 21 || sd->status.class == 4014 || sd->status.class == 4022) {
+ if (!pc_isriding(sd)) { // sd have the new value...
+ if (sd->status.class == 13)
+ sd->status.class = sd->view_class = 7;
+ else if (sd->status.class == 21)
+ sd->status.class = sd->view_class = 14;
+ else if (sd->status.class == 4014)
+ sd->status.class = sd->view_class = 4008;
+ else if (sd->status.class == 4022)
+ sd->status.class = sd->view_class = 4015;
+ }
+ } else {
+ if (pc_isriding(sd)) { // sd have the new value...
+ if (sd->disguise > 0) { // temporary prevention of crash caused by peco + disguise, will look into a better solution [Valaris] (code added by [Yor])
+ sd->status.option &= ~0x0020;
+ } else {
+ if (sd->status.class == 7)
+ sd->status.class = sd->view_class = 13;
+ else if (sd->status.class == 14)
+ sd->status.class = sd->view_class = 21;
+ else if (sd->status.class == 4008)
+ sd->status.class = sd->view_class = 4014;
+ else if (sd->status.class == 4015)
+ sd->status.class = sd->view_class = 4022;
+ else
+ sd->status.option &= ~0x0020;
+ }
+ }
+ }
+
+ clif_changeoption(&sd->bl);
+ pc_calcstatus(sd, 0);
+ clif_displaymessage(fd, msg_table[9]); // Options changed.
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_hide(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ if (sd->status.option & OPTION_HIDE) {
+ sd->status.option &= ~OPTION_HIDE;
+ clif_displaymessage(fd, msg_table[10]); // Invisible: Off
+ } else {
+ sd->status.option |= OPTION_HIDE;
+ clif_displaymessage(fd, msg_table[11]); // Invisible: On
+ }
+ clif_changeoption(&sd->bl);
+
+ return 0;
+}
+
+/*==========================================
+ * 転職する upperを指定すると転生や養子にもなれる
+ *------------------------------------------
+ */
+int atcommand_jobchange(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int job = 0, upper = -1;
+
+ if (!message || !*message || sscanf(message, "%d %d", &job, &upper) < 1) {
+ clif_displaymessage(fd, "Please, enter job ID (usage: @job/@jobchange <job ID>).");
+ return -1;
+ }
+
+ if (job == 37 ||job == 45)
+ return 0;
+
+ if ((job >= 0 && job < MAX_PC_CLASS)) {
+
+ // fix pecopeco display
+ if ((job != 13 && job != 21 && job != 4014 && job != 4022)) {
+ if (pc_isriding(sd)) {
+ if (sd->status.class == 13)
+ sd->status.class = sd->view_class = 7;
+ if (sd->status.class == 21)
+ sd->status.class = sd->view_class = 14;
+ if (sd->status.class == 4014)
+ sd->status.class = sd->view_class = 4008;
+ if (sd->status.class == 4022)
+ sd->status.class = sd->view_class = 4015;
+ sd->status.option &= ~0x0020;
+ clif_changeoption(&sd->bl);
+ pc_calcstatus(sd, 0);
+ }
+ } else {
+ if (!pc_isriding(sd)) {
+ if (job == 13)
+ job = 7;
+ if (job == 21)
+ job = 14;
+ if (job == 4014)
+ job = 4008;
+ if (job == 4022)
+ job = 4015;
+ }
+ }
+
+ if (pc_jobchange(sd, job, upper) == 0)
+ clif_displaymessage(fd, msg_table[12]); // Your job has been changed.
+ else {
+ clif_displaymessage(fd, msg_table[155]); // Impossible to change your job.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, "Please, enter a valid job ID (usage: @job/@jobchange <job ID>).");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_die(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ pc_damage(NULL, sd, sd->status.hp + 1);
+ clif_displaymessage(fd, msg_table[13]); // A pity! You've died.
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_kill(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ struct map_session_data *pl_sd;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @kill <char name>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can kill only lower or same level
+ pc_damage(NULL, pl_sd, pl_sd->status.hp + 1);
+ clif_displaymessage(fd, msg_table[14]); // Character killed.
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_alive(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ sd->status.hp = sd->status.max_hp;
+ sd->status.sp = sd->status.max_sp;
+ pc_setstand(sd);
+ if (battle_config.pc_invincible_time > 0)
+ pc_setinvincibletimer(sd, battle_config.pc_invincible_time);
+ clif_updatestatus(sd, SP_HP);
+ clif_updatestatus(sd, SP_SP);
+ clif_resurrection(&sd->bl, 1);
+ clif_displaymessage(fd, msg_table[16]); // You've been revived! It's a miracle!
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_kami(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char output[200];
+
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message) {
+ clif_displaymessage(fd, "Please, enter a message (usage: @kami <message>).");
+ return -1;
+ }
+
+ sscanf(message, "%199[^\n]", output);
+ intif_GMmessage(output, strlen(output) + 1, (*(command + 5) == 'b') ? 0x10 : 0);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_heal(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int hp = 0, sp = 0; // [Valaris] thanks to fov
+
+ sscanf(message, "%d %d", &hp, &sp);
+
+ if (hp == 0 && sp == 0) {
+ hp = sd->status.max_hp - sd->status.hp;
+ sp = sd->status.max_sp - sd->status.sp;
+ } else {
+ if (hp > 0 && (hp > sd->status.max_hp || hp > (sd->status.max_hp - sd->status.hp))) // fix positiv overflow
+ hp = sd->status.max_hp - sd->status.hp;
+ else if (hp < 0 && (hp < -sd->status.max_hp || hp < (1 - sd->status.hp))) // fix negativ overflow
+ hp = 1 - sd->status.hp;
+ if (sp > 0 && (sp > sd->status.max_sp || sp > (sd->status.max_sp - sd->status.sp))) // fix positiv overflow
+ sp = sd->status.max_sp - sd->status.sp;
+ else if (sp < 0 && (sp < -sd->status.max_sp || sp < (1 - sd->status.sp))) // fix negativ overflow
+ sp = 1 - sd->status.sp;
+ }
+
+ if (hp > 0) // display like heal
+ clif_heal(fd, SP_HP, hp);
+ else if (hp < 0) // display like damage
+ clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0 , 4, 0);
+ if (sp > 0) // no display when we lost SP
+ clif_heal(fd, SP_SP, sp);
+
+ if (hp != 0 || sp != 0) {
+ pc_heal(sd, hp, sp);
+ if (hp >= 0 && sp >= 0)
+ clif_displaymessage(fd, msg_table[17]); // HP, SP recovered.
+ else
+ clif_displaymessage(fd, msg_table[156]); // HP or/and SP modified.
+ } else {
+ clif_displaymessage(fd, msg_table[157]); // HP and SP are already with the good value.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @item command (usage: @item <name/id_of_item> <quantity>) (modified by [Yor] for pet_egg)
+ *------------------------------------------
+ */
+int atcommand_item(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char item_name[100];
+ int number = 0, item_id, flag;
+ struct item item_tmp;
+ struct item_data *item_data;
+ int get_count, i, pet_id;
+
+ memset(item_name, '\0', sizeof(item_name));
+
+ if (!message || !*message || sscanf(message, "%99s %d", item_name, &number) < 1) {
+ clif_displaymessage(fd, "Please, enter an item name/id (usage: @item <item name or ID> [quantity]).");
+ return -1;
+ }
+
+ if (number <= 0)
+ number = 1;
+
+ item_id = 0;
+ if ((item_data = itemdb_searchname(item_name)) != NULL ||
+ (item_data = itemdb_exists(atoi(item_name))) != NULL)
+ item_id = item_data->nameid;
+
+ if (item_id >= 500) {
+ get_count = number;
+ // check pet egg
+ pet_id = search_petDB_index(item_id, PET_EGG);
+ if (item_data->type == 4 || item_data->type == 5 ||
+ item_data->type == 7 || item_data->type == 8) {
+ get_count = 1;
+ }
+ for (i = 0; i < number; i += get_count) {
+ // if pet egg
+ if (pet_id >= 0) {
+ sd->catch_target_class = pet_db[pet_id].class;
+ intif_create_pet(sd->status.account_id, sd->status.char_id,
+ pet_db[pet_id].class, mob_db[pet_db[pet_id].class].lv,
+ pet_db[pet_id].EggID, 0, pet_db[pet_id].intimate,
+ 100, 0, 1, pet_db[pet_id].jname);
+ // if not pet egg
+ } else {
+ memset(&item_tmp, 0, sizeof(item_tmp));
+ item_tmp.nameid = item_id;
+ item_tmp.identify = 1;
+ if ((flag = pc_additem((struct map_session_data*)sd, &item_tmp, get_count)))
+ clif_additem((struct map_session_data*)sd, 0, 0, flag);
+ }
+ }
+ clif_displaymessage(fd, msg_table[18]); // Item created.
+ } else {
+ clif_displaymessage(fd, msg_table[19]); // Invalid item ID or name.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_item2(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct item item_tmp;
+ struct item_data *item_data;
+ char item_name[100];
+ int item_id, number = 0;
+ int identify = 0, refine = 0, attr = 0;
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+ int flag;
+ int loop, get_count, i;
+
+ memset(item_name, '\0', sizeof(item_name));
+
+ if (!message || !*message || sscanf(message, "%99s %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9) {
+ clif_displaymessage(fd, "Please, enter all informations (usage: @item2 <item name or ID> <quantity>");
+ clif_displaymessage(fd, " <Identify_flag> <refine> <attribut> <Card1> <Card2> <Card3> <Card4>).");
+ return -1;
+ }
+
+ if (number <= 0)
+ number = 1;
+
+ item_id = 0;
+ if ((item_data = itemdb_searchname(item_name)) != NULL ||
+ (item_data = itemdb_exists(atoi(item_name))) != NULL)
+ item_id = item_data->nameid;
+
+ if (item_id > 500) {
+ loop = 1;
+ get_count = number;
+ if (item_data->type == 4 || item_data->type == 5 ||
+ item_data->type == 7 || item_data->type == 8) {
+ loop = number;
+ get_count = 1;
+ if (item_data->type == 7) {
+ identify = 1;
+ refine = 0;
+ }
+ if (item_data->type == 8)
+ refine = 0;
+ if (refine > 10)
+ refine = 10;
+ } else {
+ identify = 1;
+ refine = attr = 0;
+ }
+ for (i = 0; i < loop; i++) {
+ memset(&item_tmp, 0, sizeof(item_tmp));
+ item_tmp.nameid = item_id;
+ item_tmp.identify = identify;
+ item_tmp.refine = refine;
+ item_tmp.attribute = attr;
+ item_tmp.card[0] = c1;
+ item_tmp.card[1] = c2;
+ item_tmp.card[2] = c3;
+ item_tmp.card[3] = c4;
+ if ((flag = pc_additem(sd, &item_tmp, get_count)))
+ clif_additem(sd, 0, 0, flag);
+ }
+ clif_displaymessage(fd, msg_table[18]); // Item created.
+ } else {
+ clif_displaymessage(fd, msg_table[19]); // Invalid item ID or name.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_itemreset(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int i;
+
+ for (i = 0; i < MAX_INVENTORY; i++) {
+ if (sd->status.inventory[i].amount && sd->status.inventory[i].equip == 0)
+ pc_delitem(sd, i, sd->status.inventory[i].amount, 0);
+ }
+ clif_displaymessage(fd, msg_table[20]); // All of your items have been removed.
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_itemcheck(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ pc_checkitem(sd);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_baselevelup(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int level, i;
+
+ if (!message || !*message || (level = atoi(message)) == 0) {
+ clif_displaymessage(fd, "Please, enter a level adjustement (usage: @lvup/@blevel/@baselvlup <number of levels>).");
+ return -1;
+ }
+
+ if (level > 0) {
+ if (sd->status.base_level == battle_config.maximum_level) { // check for max level by Valaris
+ clif_displaymessage(fd, msg_table[47]); // Base level can't go any higher.
+ return -1;
+ } // End Addition
+ if (level > battle_config.maximum_level || level > (battle_config.maximum_level - sd->status.base_level)) // fix positiv overflow
+ level = battle_config.maximum_level - sd->status.base_level;
+ for (i = 1; i <= level; i++)
+ sd->status.status_point += (sd->status.base_level + i + 14) / 5;
+ sd->status.base_level += level;
+ clif_updatestatus(sd, SP_BASELEVEL);
+ clif_updatestatus(sd, SP_NEXTBASEEXP);
+ clif_updatestatus(sd, SP_STATUSPOINT);
+ pc_calcstatus(sd, 0);
+ pc_heal(sd, sd->status.max_hp, sd->status.max_sp);
+ clif_misceffect(&sd->bl, 0);
+ clif_displaymessage(fd, msg_table[21]); // Base level raised.
+ } else {
+ if (sd->status.base_level == 1) {
+ clif_displaymessage(fd, msg_table[158]); // Base level can't go any lower.
+ return -1;
+ }
+ if (level < -battle_config.maximum_level || level < (1 - sd->status.base_level)) // fix negativ overflow
+ level = 1 - sd->status.base_level;
+ if (sd->status.status_point > 0) {
+ for (i = 0; i > level; i--)
+ sd->status.status_point -= (sd->status.base_level + i + 14) / 5;
+ if (sd->status.status_point < 0)
+ sd->status.status_point = 0;
+ clif_updatestatus(sd, SP_STATUSPOINT);
+ } // to add: remove status points from stats
+ sd->status.base_level += level;
+ clif_updatestatus(sd, SP_BASELEVEL);
+ clif_updatestatus(sd, SP_NEXTBASEEXP);
+ pc_calcstatus(sd, 0);
+ clif_displaymessage(fd, msg_table[22]); // Base level lowered.
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_joblevelup(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int up_level = 50, level;
+
+ if (!message || !*message || (level = atoi(message)) == 0) {
+ clif_displaymessage(fd, "Please, enter a level adjustement (usage: @joblvup/@jlevel/@joblvlup <number of levels>).");
+ return -1;
+ }
+
+ if (sd->status.class == 0 || sd->status.class == 4001)
+ up_level -= 40;
+ else if ((sd->status.class > 4007 && sd->status.class < 4024) || sd->status.class == 23)
+ up_level += 20;
+
+ if (level > 0) {
+ if (sd->status.job_level == up_level) {
+ clif_displaymessage(fd, msg_table[23]); // Job level can't go any higher.
+ return -1;
+ }
+ if (level > up_level || level > (up_level - sd->status.job_level)) // fix positiv overflow
+ level = up_level - sd->status.job_level;
+ sd->status.job_level += level;
+ clif_updatestatus(sd, SP_JOBLEVEL);
+ clif_updatestatus(sd, SP_NEXTJOBEXP);
+ sd->status.skill_point += level;
+ clif_updatestatus(sd, SP_SKILLPOINT);
+ pc_calcstatus(sd, 0);
+ clif_misceffect(&sd->bl, 1);
+ clif_displaymessage(fd, msg_table[24]); // Job level raised.
+ } else {
+ if (sd->status.job_level == 1) {
+ clif_displaymessage(fd, msg_table[159]); // Job level can't go any lower.
+ return -1;
+ }
+ if (level < -up_level || level < (1 - sd->status.job_level)) // fix negativ overflow
+ level = 1 - sd->status.job_level;
+ sd->status.job_level += level;
+ clif_updatestatus(sd, SP_JOBLEVEL);
+ clif_updatestatus(sd, SP_NEXTJOBEXP);
+ if (sd->status.skill_point > 0) {
+ sd->status.skill_point += level;
+ if (sd->status.skill_point < 0)
+ sd->status.skill_point = 0;
+ clif_updatestatus(sd, SP_SKILLPOINT);
+ } // to add: remove status points from skills
+ pc_calcstatus(sd, 0);
+ clif_displaymessage(fd, msg_table[25]); // Job level lowered.
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_help(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char buf[2048], w1[2048], w2[2048];
+ int i, gm_level;
+ FILE* fp;
+
+ memset(buf, '\0', sizeof(buf));
+
+ if ((fp = fopen(help_txt, "r")) != NULL) {
+ clif_displaymessage(fd, msg_table[26]); // Help commands:
+ gm_level = pc_isGM(sd);
+ while(fgets(buf, sizeof(buf) - 1, fp) != NULL) {
+ if (buf[0] == '/' && buf[1] == '/')
+ continue;
+ for (i = 0; buf[i] != '\0'; i++) {
+ if (buf[i] == '\r' || buf[i] == '\n') {
+ buf[i] = '\0';
+ break;
+ }
+ }
+ if (sscanf(buf, "%2047[^:]:%2047[^\n]", w1, w2) < 2)
+ clif_displaymessage(fd, buf);
+ else if (gm_level >= atoi(w1))
+ clif_displaymessage(fd, w2);
+ }
+ fclose(fp);
+ } else {
+ clif_displaymessage(fd, msg_table[27]); // File help.txt not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_gm(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char password[100];
+
+ memset(password, '\0', sizeof(password));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", password) < 1) {
+ clif_displaymessage(fd, "Please, enter a password (usage: @gm <password>).");
+ return -1;
+ }
+
+ if (pc_isGM(sd)) { // a GM can not use this function. only a normal player (become gm is not for gm!)
+ clif_displaymessage(fd, msg_table[50]); // You already have some GM powers.
+ return -1;
+ } else
+ chrif_changegm(sd->status.account_id, password, strlen(password) + 1);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_pvpoff(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ int i;
+
+ if (battle_config.pk_mode) { //disable command if server is in PK mode [Valaris]
+ clif_displaymessage(fd, msg_table[52]); // This option cannot be used in PK Mode.
+ return -1;
+ }
+
+ if (map[sd->bl.m].flag.pvp) {
+ map[sd->bl.m].flag.pvp = 0;
+ clif_send0199(sd->bl.m, 0);
+ for (i = 0; i < fd_max; i++) { //人数分ループ
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
+ if (sd->bl.m == pl_sd->bl.m) {
+ clif_pvpset(pl_sd, 0, 0, 2);
+ if (pl_sd->pvp_timer != -1) {
+ delete_timer(pl_sd->pvp_timer, pc_calc_pvprank_timer);
+ pl_sd->pvp_timer = -1;
+ }
+ }
+ }
+ }
+ clif_displaymessage(fd, msg_table[31]); // PvP: Off.
+ } else {
+ clif_displaymessage(fd, msg_table[160]); // PvP is already Off.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_pvpon(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ int i;
+
+ if (battle_config.pk_mode) { //disable command if server is in PK mode [Valaris]
+ clif_displaymessage(fd, msg_table[52]); // This option cannot be used in PK Mode.
+ return -1;
+ }
+
+ if (!map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.nopvp) {
+ map[sd->bl.m].flag.pvp = 1;
+ clif_send0199(sd->bl.m, 1);
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
+ if (sd->bl.m == pl_sd->bl.m && pl_sd->pvp_timer == -1) {
+ pl_sd->pvp_timer = add_timer(gettick() + 200,
+ pc_calc_pvprank_timer, pl_sd->bl.id, 0);
+ pl_sd->pvp_rank = 0;
+ pl_sd->pvp_lastusers = 0;
+ pl_sd->pvp_point = 5;
+ }
+ }
+ }
+ clif_displaymessage(fd, msg_table[32]); // PvP: On.
+ } else {
+ clif_displaymessage(fd, msg_table[161]); // PvP is already On.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_gvgoff(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ if (map[sd->bl.m].flag.gvg) {
+ map[sd->bl.m].flag.gvg = 0;
+ clif_send0199(sd->bl.m, 0);
+ clif_displaymessage(fd, msg_table[33]); // GvG: Off.
+ } else {
+ clif_displaymessage(fd, msg_table[162]); // GvG is already Off.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_gvgon(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ if (!map[sd->bl.m].flag.gvg) {
+ map[sd->bl.m].flag.gvg = 1;
+ clif_send0199(sd->bl.m, 3);
+ clif_displaymessage(fd, msg_table[34]); // GvG: On.
+ } else {
+ clif_displaymessage(fd, msg_table[163]); // GvG is already On.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_model(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int hair_style = 0, hair_color = 0, cloth_color = 0;
+ char output[200];
+
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%d %d %d", &hair_style, &hair_color, &cloth_color) < 1) {
+ sprintf(output, "Please, enter at least a value (usage: @model <hair ID: %d-%d> <hair color: %d-%d> <clothes color: %d-%d>).",
+ MIN_HAIR_STYLE, MAX_HAIR_STYLE, MIN_HAIR_COLOR, MAX_HAIR_COLOR, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR);
+ clif_displaymessage(fd, output);
+ return -1;
+ }
+
+ if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE &&
+ hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR &&
+ cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) {
+ //服の色変更
+ if (cloth_color != 0 && sd->status.sex == 1 && (sd->status.class == 12 || sd->status.class == 17)) {
+ //服の色未実装職の判定
+ clif_displaymessage(fd, msg_table[35]); // You can't use this command with this class.
+ return -1;
+ } else {
+ pc_changelook(sd, LOOK_HAIR, hair_style);
+ pc_changelook(sd, LOOK_HAIR_COLOR, hair_color);
+ pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color);
+ clif_displaymessage(fd, msg_table[36]); // Appearence changed.
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[37]); // An invalid number was specified.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @dye && @ccolor
+ *------------------------------------------
+ */
+int atcommand_dye(const int fd, struct map_session_data* sd, const char* command, const char* message)
+{
+ int cloth_color = 0;
+ char output[200];
+
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%d", &cloth_color) < 1) {
+ sprintf(output, "Please, enter a clothes color (usage: @dye/@ccolor <clothes color: %d-%d>).", MIN_CLOTH_COLOR, MAX_CLOTH_COLOR);
+ clif_displaymessage(fd, output);
+ return -1;
+ }
+
+ if (cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) {
+ if (cloth_color != 0 && sd->status.sex == 1 && (sd->status.class == 12 || sd->status.class == 17)) {
+ clif_displaymessage(fd, msg_table[35]); // You can't use this command with this class.
+ return -1;
+ } else {
+ pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color);
+ clif_displaymessage(fd, msg_table[36]); // Appearence changed.
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[37]); // An invalid number was specified.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @chardye by [MouseJstr]
+ *------------------------------------------
+ */
+int
+atcommand_chardye(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ return 0;
+}
+
+/*==========================================
+ * @hairstyle && @hstyle
+ *------------------------------------------
+ */
+int atcommand_hair_style(const int fd, struct map_session_data* sd, const char* command, const char* message)
+{
+ int hair_style = 0;
+ char output[200];
+
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%d", &hair_style) < 1) {
+ sprintf(output, "Please, enter a hair style (usage: @hairstyle/@hstyle <hair ID: %d-%d>).", MIN_HAIR_STYLE, MAX_HAIR_STYLE);
+ clif_displaymessage(fd, output);
+ return -1;
+ }
+
+ if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE) {
+ if (hair_style != 0 && sd->status.sex == 1 && (sd->status.class == 12 || sd->status.class == 17)) {
+ clif_displaymessage(fd, msg_table[35]); // You can't use this command with this class.
+ return -1;
+ } else {
+ pc_changelook(sd, LOOK_HAIR, hair_style);
+ clif_displaymessage(fd, msg_table[36]); // Appearence changed.
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[37]); // An invalid number was specified.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @charhairstyle by [MouseJstr]
+ *------------------------------------------
+ */
+int
+atcommand_charhairstyle(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ return 0;
+}
+
+/*==========================================
+ * @haircolor && @hcolor
+ *------------------------------------------
+ */
+int atcommand_hair_color(const int fd, struct map_session_data* sd, const char* command, const char* message)
+{
+ int hair_color = 0;
+ char output[200];
+
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%d", &hair_color) < 1) {
+ sprintf(output, "Please, enter a hair color (usage: @haircolor/@hcolor <hair color: %d-%d>).", MIN_HAIR_COLOR, MAX_HAIR_COLOR);
+ clif_displaymessage(fd, output);
+ return -1;
+ }
+
+ if (hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR) {
+ if (hair_color != 0 && sd->status.sex == 1 && (sd->status.class == 12 || sd->status.class == 17)) {
+ clif_displaymessage(fd, msg_table[35]); // You can't use this command with this class.
+ return -1;
+ } else {
+ pc_changelook(sd, LOOK_HAIR_COLOR, hair_color);
+ clif_displaymessage(fd, msg_table[36]); // Appearence changed.
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[37]); // An invalid number was specified.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @charhaircolor by [MouseJstr]
+ *------------------------------------------
+ */
+int
+atcommand_charhaircolor(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ return 0;
+}
+
+/*==========================================
+ * @go [city_number/city_name]: improved by [yor] to add city names and help
+ *------------------------------------------
+ */
+int atcommand_go(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int i;
+ int town;
+ char map_name[100];
+ char output[200];
+ int m;
+
+ struct { char map[16]; int x, y; } data[] = {
+ { "prontera.gat", 156, 191 }, // 0=Prontera
+ { "morocc.gat", 156, 93 }, // 1=Morroc
+ { "geffen.gat", 119, 59 }, // 2=Geffen
+ { "payon.gat", 162, 233 }, // 3=Payon
+ { "alberta.gat", 192, 147 }, // 4=Alberta
+ { "izlude.gat", 128, 114 }, // 5=Izlude
+ { "aldebaran.gat",140, 131 }, // 6=Al de Baran
+ { "xmas.gat", 147, 134 }, // 7=Lutie
+ { "comodo.gat", 209, 143 }, // 8=Comodo
+ { "yuno.gat", 157, 51 }, // 9=Yuno
+ { "amatsu.gat", 198, 84 }, // 10=Amatsu
+ { "gonryun.gat", 160, 120 }, // 11=Gon Ryun
+ { "umbala.gat", 89, 157 }, // 12=Umbala
+ { "niflheim.gat", 21, 153 }, // 13=Niflheim
+ { "louyang.gat", 217, 40 }, // 14=Lou Yang
+ { "new_1-1.gat", 53, 111 }, // 15=Start point
+ { "sec_pri.gat", 23, 61 }, // 16=Prison
+ };
+
+ memset(map_name, '\0', sizeof(map_name));
+ memset(output, '\0', sizeof(output));
+
+ // get the number
+ town = atoi(message);
+
+ // if no value, display all value
+ if (!message || !*message || sscanf(message, "%99s", map_name) < 1 || town < -3 || town >= (int)(sizeof(data) / sizeof(data[0]))) {
+ clif_displaymessage(fd, msg_table[38]); // Invalid location number or name.
+ clif_displaymessage(fd, msg_table[82]); // Please, use one of this number/name:
+ clif_displaymessage(fd, "-3=(Memo point 2) 4=Alberta 11=Gon Ryun");
+ clif_displaymessage(fd, "-2=(Memo point 1) 5=Izlude 12=Umbala");
+ clif_displaymessage(fd, "-1=(Memo point 0) 6=Al de Baran 13=Niflheim");
+ clif_displaymessage(fd, " 0=Prontera 7=Lutie 14=Lou Yang");
+ clif_displaymessage(fd, " 1=Morroc 8=Comodo 15=Start point");
+ clif_displaymessage(fd, " 2=Geffen 9=Yuno 16=Prison");
+ clif_displaymessage(fd, " 3=Payon 10=Amatsu");
+ return -1;
+ } else {
+ // get possible name of the city and add .gat if not in the name
+ map_name[sizeof(map_name)-1] = '\0';
+ for (i = 0; map_name[i]; i++)
+ map_name[i] = tolower(map_name[i]);
+ if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat)
+ strcat(map_name, ".gat");
+ // try to see if it's a name, and not a number (try a lot of possibilities, write errors and abbreviations too)
+ if (strncmp(map_name, "prontera.gat", 3) == 0) { // 3 first characters
+ town = 0;
+ } else if (strncmp(map_name, "morocc.gat", 3) == 0) { // 3 first characters
+ town = 1;
+ } else if (strncmp(map_name, "geffen.gat", 3) == 0) { // 3 first characters
+ town = 2;
+ } else if (strncmp(map_name, "payon.gat", 3) == 0 || // 3 first characters
+ strncmp(map_name, "paion.gat", 3) == 0) { // writing error (3 first characters)
+ town = 3;
+ } else if (strncmp(map_name, "alberta.gat", 3) == 0) { // 3 first characters
+ town = 4;
+ } else if (strncmp(map_name, "izlude.gat", 3) == 0 || // 3 first characters
+ strncmp(map_name, "islude.gat", 3) == 0) { // writing error (3 first characters)
+ town = 5;
+ } else if (strncmp(map_name, "aldebaran.gat", 3) == 0 || // 3 first characters
+ strcmp(map_name, "al.gat") == 0) { // al (de baran)
+ town = 6;
+ } else if (strncmp(map_name, "lutie.gat", 3) == 0 || // name of the city, not name of the map (3 first characters)
+ strcmp(map_name, "christmas.gat") == 0 || // name of the symbol
+ strncmp(map_name, "xmas.gat", 3) == 0 || // 3 first characters
+ strncmp(map_name, "x-mas.gat", 3) == 0) { // writing error (3 first characters)
+ town = 7;
+ } else if (strncmp(map_name, "comodo.gat", 3) == 0) { // 3 first characters
+ town = 8;
+ } else if (strncmp(map_name, "yuno.gat", 3) == 0) { // 3 first characters
+ town = 9;
+ } else if (strncmp(map_name, "amatsu.gat", 3) == 0 || // 3 first characters
+ strncmp(map_name, "ammatsu.gat", 3) == 0) { // writing error (3 first characters)
+ town = 10;
+ } else if (strncmp(map_name, "gonryun.gat", 3) == 0) { // 3 first characters
+ town = 11;
+ } else if (strncmp(map_name, "umbala.gat", 3) == 0) { // 3 first characters
+ town = 12;
+ } else if (strncmp(map_name, "niflheim.gat", 3) == 0) { // 3 first characters
+ town = 13;
+ } else if (strncmp(map_name, "louyang.gat", 3) == 0) { // 3 first characters
+ town = 14;
+ } else if (strncmp(map_name, "new_1-1.gat", 3) == 0 || // 3 first characters (or "newbies")
+ strncmp(map_name, "startpoint.gat", 3) == 0 || // name of the position (3 first characters)
+ strncmp(map_name, "begining.gat", 3) == 0) { // name of the position (3 first characters)
+ town = 15;
+ } else if (strncmp(map_name, "sec_pri.gat", 3) == 0 || // 3 first characters
+ strncmp(map_name, "prison.gat", 3) == 0 || // name of the position (3 first characters)
+ strncmp(map_name, "jails.gat", 3) == 0) { // name of the position
+ town = 16;
+ }
+
+ if (town >= -3 && town <= -1) {
+ if (sd->status.memo_point[-town-1].map[0]) {
+ m = map_mapname2mapid(sd->status.memo_point[-town-1].map);
+ if (m >= 0 && map[m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp you to this memo map.");
+ return -1;
+ }
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp you from your actual map.");
+ return -1;
+ }
+ if (pc_setpos(sd, sd->status.memo_point[-town-1].map, sd->status.memo_point[-town-1].x, sd->status.memo_point[-town-1].y, 3) == 0) {
+ clif_displaymessage(fd, msg_table[0]); // Warped.
+ } else {
+ clif_displaymessage(fd, msg_table[1]); // Map not found.
+ return -1;
+ }
+ } else {
+ sprintf(output, msg_table[164], -town-1); // Your memo point #%d doesn't exist.
+ clif_displaymessage(fd, output);
+ return -1;
+ }
+ } else if (town >= 0 && town < (int)(sizeof(data) / sizeof(data[0]))) {
+ m = map_mapname2mapid(data[town].map);
+ if (m >= 0 && map[m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp you to this destination map.");
+ return -1;
+ }
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp you from your actual map.");
+ return -1;
+ }
+ if (pc_setpos(sd, data[town].map, data[town].x, data[town].y, 3) == 0) {
+ clif_displaymessage(fd, msg_table[0]); // Warped.
+ } else {
+ clif_displaymessage(fd, msg_table[1]); // Map not found.
+ return -1;
+ }
+ } else { // if you arrive here, you have an error in town variable when reading of names
+ clif_displaymessage(fd, msg_table[38]); // Invalid location number or name.
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_monster(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char name[100];
+ char monster[100];
+ char output[200];
+ int mob_id;
+ int number = 0;
+ int x = 0, y = 0;
+ int count;
+ int i, j, k;
+ int mx, my, range;
+
+ memset(name, '\0', sizeof(name));
+ memset(monster, '\0', sizeof(monster));
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message ||
+ (sscanf(message, "\"%[^\"]\" %99s %d %d %d", name, monster, &number, &x, &y) < 2 &&
+ sscanf(message, "%99s \"%[^\"]\" %d %d %d", monster, name, &number, &x, &y) < 2 &&
+ sscanf(message, "%99s %99s %d %d %d", name, monster, &number, &x, &y) < 2)) {
+ clif_displaymessage(fd, msg_table[80]); // Give a display name and monster name/id please.
+ return -1;
+ }
+
+ if ((mob_id = mobdb_searchname(monster)) == 0) // check name first (to avoid possible name begining by a number)
+ mob_id = mobdb_checkid(atoi(monster));
+
+ if (mob_id == 0) {
+ clif_displaymessage(fd, msg_table[40]); // Invalid monster ID or name.
+ return -1;
+ }
+
+ if (mob_id == 1288) {
+ clif_displaymessage(fd, msg_table[83]); // Cannot spawn emperium.
+ return -1;
+ }
+
+ if (number <= 0)
+ number = 1;
+
+ if (strlen(name) < 1)
+ strcpy(name, "--ja--");
+
+ // If value of atcommand_spawn_quantity_limit directive is greater than or equal to 1 and quantity of monsters is greater than value of the directive
+ if (battle_config.atc_spawn_quantity_limit >= 1 && number > battle_config.atc_spawn_quantity_limit)
+ number = battle_config.atc_spawn_quantity_limit;
+
+ if (battle_config.etc_log)
+ printf("%s monster='%s' name='%s' id=%d count=%d (%d,%d)\n", command, monster, name, mob_id, number, x, y);
+
+ count = 0;
+ range = sqrt(number) / 2;
+ range = range * 2 + 5; // calculation of an odd number (+ 4 area around)
+ for (i = 0; i < number; i++) {
+ j = 0;
+ k = 0;
+ while(j++ < 8 && k == 0) { // try 8 times to spawn the monster (needed for close area)
+ if (x <= 0)
+ mx = sd->bl.x + (rand() % range - (range / 2));
+ else
+ mx = x;
+ if (y <= 0)
+ my = sd->bl.y + (rand() % range - (range / 2));
+ else
+ my = y;
+ k = mob_once_spawn((struct map_session_data*)sd, "this", mx, my, name, mob_id, 1, "");
+ }
+ count += (k != 0) ? 1 : 0;
+ }
+
+ if (count != 0)
+ if (number == count)
+ clif_displaymessage(fd, msg_table[39]); // All monster summoned!
+ else {
+ sprintf(output, msg_table[240], count); // %d monster(s) summoned!
+ clif_displaymessage(fd, output);
+ }
+ else {
+ clif_displaymessage(fd, msg_table[40]); // Invalid monster ID or name.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_spawn(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message) {
+ char name[100];
+ char monster[100];
+ char output[200];
+ int mob_id;
+ int number = 0;
+ int x = 0, y = 0;
+ int count;
+ int i, j, k;
+ int mx, my, range;
+
+ memset(name, '\0', sizeof(name));
+ memset(monster, '\0', sizeof(monster));
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message ||
+ (sscanf(message, "\"%[^\"]\" %99s %d %d %d", name, monster, &number, &x, &y) < 2 &&
+ sscanf(message, "%99s \"%[^\"]\" %d %d %d", monster, name, &number, &x, &y) < 2 &&
+ sscanf(message, "%99s %d %99s %d %d", monster, &number, name, &x, &y) < 1)) {
+ clif_displaymessage(fd, msg_table[143]); // Give a monster name/id please.
+ return -1;
+ }
+
+ // If monster identifier/name argument is a name
+ if ((mob_id = mobdb_searchname(monster)) == 0) // check name first (to avoid possible name begining by a number)
+ mob_id = mobdb_checkid(atoi(monster));
+
+ if (mob_id == 0) {
+ clif_displaymessage(fd, msg_table[40]); // Invalid monster ID or name.
+ return -1;
+ }
+
+ if (mob_id == 1288) {
+ clif_displaymessage(fd, msg_table[83]); // Cannot spawn emperium.
+ return -1;
+ }
+
+ if (number <= 0)
+ number = 1;
+
+ if (strlen(name) < 1)
+ strcpy(name, "--ja--");
+
+ // If value of atcommand_spawn_quantity_limit directive is greater than or equal to 1 and quantity of monsters is greater than value of the directive
+ if (battle_config.atc_spawn_quantity_limit >= 1 && number > battle_config.atc_spawn_quantity_limit)
+ number = battle_config.atc_spawn_quantity_limit;
+
+ if (battle_config.etc_log)
+ printf("%s monster='%s' name='%s' id=%d count=%d (%d,%d)\n", command, monster, name, mob_id, number, x, y);
+
+ count = 0;
+ range = sqrt(number) / 2;
+ range = range * 2 + 5; // calculation of an odd number (+ 4 area around)
+ for (i = 0; i < number; i++) {
+ j = 0;
+ k = 0;
+ while(j++ < 8 && k == 0) { // try 8 times to spawn the monster (needed for close area)
+ if (x <= 0)
+ mx = sd->bl.x + (rand() % range - (range / 2));
+ else
+ mx = x;
+ if (y <= 0)
+ my = sd->bl.y + (rand() % range - (range / 2));
+ else
+ my = y;
+ k = mob_once_spawn((struct map_session_data*)sd, "this", mx, my, name, mob_id, 1, "");
+ }
+ count += (k != 0) ? 1 : 0;
+ }
+
+ if (count != 0)
+ if (number == count)
+ clif_displaymessage(fd, msg_table[39]); // All monster summoned!
+ else {
+ sprintf(output, msg_table[240], count); // %d monster(s) summoned!
+ clif_displaymessage(fd, output);
+ }
+ else {
+ clif_displaymessage(fd, msg_table[40]); // Invalid monster ID or name.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void atcommand_killmonster_sub(
+ const int fd, struct map_session_data* sd, const char* message,
+ const int drop)
+{
+ int map_id;
+ char map_name[100];
+
+ memset(map_name, '\0', sizeof(map_name));
+
+ if (!message || !*message || sscanf(message, "%99s", map_name) < 1)
+ map_id = sd->bl.m;
+ else {
+ if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat)
+ strcat(map_name, ".gat");
+ if ((map_id = map_mapname2mapid(map_name)) < 0)
+ map_id = sd->bl.m;
+ }
+
+ map_foreachinarea(atkillmonster_sub, map_id, 0, 0, map[map_id].xs, map[map_id].ys, BL_MOB, drop);
+
+ clif_displaymessage(fd, msg_table[165]); // All monsters killed!
+
+ return;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_killmonster(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ atcommand_killmonster_sub(fd, sd, message, 1);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_killmonster2(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ atcommand_killmonster_sub(fd, sd, message, 0);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_refine(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int i, position = 0, refine = 0, current_position, final_refine;
+ int count;
+ char output[200];
+
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%d %d", &position, &refine) < 2) {
+ clif_displaymessage(fd, "Please, enter a position and a amount (usage: @refine <equip position> <+/- amount>).");
+ return -1;
+ }
+
+ if (refine < -10)
+ refine = -10;
+ else if (refine > 10)
+ refine = 10;
+ else if (refine == 0)
+ refine = 1;
+
+ count = 0;
+ for (i = 0; i < MAX_INVENTORY; i++) {
+ if (sd->status.inventory[i].nameid && // 該当個所の装備を精錬する
+ (sd->status.inventory[i].equip & position ||
+ (sd->status.inventory[i].equip && !position))) {
+ final_refine = sd->status.inventory[i].refine + refine;
+ if (final_refine > 10)
+ final_refine = 10;
+ else if (final_refine < 0)
+ final_refine = 0;
+ if (sd->status.inventory[i].refine != final_refine) {
+ sd->status.inventory[i].refine = final_refine;
+ current_position = sd->status.inventory[i].equip;
+ pc_unequipitem(sd, i, 0);
+ clif_refine(fd, sd, 0, i, sd->status.inventory[i].refine);
+ clif_delitem(sd, i, 1);
+ clif_additem(sd, i, 1, 0);
+ pc_equipitem(sd, i, current_position);
+ clif_misceffect((struct block_list*)&sd->bl, 3);
+ count++;
+ }
+ }
+ }
+
+ if (count == 0)
+ clif_displaymessage(fd, msg_table[166]); // No item has been refined!
+ else if (count == 1)
+ clif_displaymessage(fd, msg_table[167]); // 1 item has been refined!
+ else {
+ sprintf(output, msg_table[168], count); // %d items have been refined!
+ clif_displaymessage(fd, output);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_produce(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char item_name[100];
+ int item_id, attribute = 0, star = 0;
+ int flag = 0;
+ struct item_data *item_data;
+ struct item tmp_item;
+ char output[200];
+
+ memset(output, '\0', sizeof(output));
+ memset(item_name, '\0', sizeof(item_name));
+
+ if (!message || !*message || sscanf(message, "%99s %d %d", item_name, &attribute, &star) < 1) {
+ clif_displaymessage(fd, "Please, enter at least an item name/id (usage: @produce <equip name or equip ID> <element> <# of very's>).");
+ return -1;
+ }
+
+ item_id = 0;
+ if ((item_data = itemdb_searchname(item_name)) != NULL ||
+ (item_data = itemdb_exists(atoi(item_name))) != NULL)
+ item_id = item_data->nameid;
+
+ if (itemdb_exists(item_id) &&
+ (item_id <= 500 || item_id > 1099) &&
+ (item_id < 4001 || item_id > 4148) &&
+ (item_id < 7001 || item_id > 10019) &&
+ itemdb_isequip(item_id)) {
+ if (attribute < MIN_ATTRIBUTE || attribute > MAX_ATTRIBUTE)
+ attribute = ATTRIBUTE_NORMAL;
+ if (star < MIN_STAR || star > MAX_STAR)
+ star = 0;
+ memset(&tmp_item, 0, sizeof tmp_item);
+ tmp_item.nameid = item_id;
+ tmp_item.amount = 1;
+ tmp_item.identify = 1;
+ tmp_item.card[0] = 0x00ff;
+ tmp_item.card[1] = ((star * 5) << 8) + attribute;
+ *((unsigned long *)(&tmp_item.card[2])) = sd->char_id;
+ clif_produceeffect(sd, 0, item_id); // 製造エフェクトパケット
+ clif_misceffect(&sd->bl, 3); // 他人にも成功を通知
+ if ((flag = pc_additem(sd, &tmp_item, 1)))
+ clif_additem(sd, 0, 0, flag);
+ } else {
+ if (battle_config.error_log)
+ printf("@produce NOT WEAPON [%d]\n", item_id);
+ if (item_id != 0 && itemdb_exists(item_id))
+ sprintf(output, msg_table[169], item_id, item_data->name); // This item (%d: '%s') is not an equipment.
+ else
+ sprintf(output, msg_table[170]); // This item is not an equipment.
+ clif_displaymessage(fd, output);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * Sub-function to display actual memo points
+ *------------------------------------------
+ */
+void atcommand_memo_sub(struct map_session_data* sd) {
+ int i;
+ char output[200];
+
+ memset(output, '\0', sizeof(output));
+
+ clif_displaymessage(sd->fd, "Your actual memo positions are (except respawn point):");
+ for (i = MIN_PORTAL_MEMO; i <= MAX_PORTAL_MEMO; i++) {
+ if (sd->status.memo_point[i].map[0])
+ sprintf(output, "%d - %s (%d,%d)", i, sd->status.memo_point[i].map, sd->status.memo_point[i].x, sd->status.memo_point[i].y);
+ else
+ sprintf(output, msg_table[171], i); // %d - void
+ clif_displaymessage(sd->fd, output);
+ }
+
+ return;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_memo(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int position = 0;
+ char output[200];
+
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%d", &position) < 1)
+ atcommand_memo_sub(sd);
+ else {
+ if (position >= MIN_PORTAL_MEMO && position <= MAX_PORTAL_MEMO) {
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to memo this map.");
+ return -1;
+ }
+ if (sd->status.memo_point[position].map[0]) {
+ sprintf(output, msg_table[172], position, sd->status.memo_point[position].map, sd->status.memo_point[position].x, sd->status.memo_point[position].y); // You replace previous memo position %d - %s (%d,%d).
+ clif_displaymessage(fd, output);
+ }
+ memcpy(sd->status.memo_point[position].map, map[sd->bl.m].name, 24);
+ sd->status.memo_point[position].x = sd->bl.x;
+ sd->status.memo_point[position].y = sd->bl.y;
+ clif_skill_memo(sd, 0);
+ if (pc_checkskill(sd, AL_WARP) <= (position + 1))
+ clif_displaymessage(fd, msg_table[173]); // Note: you don't have the 'Warp' skill level to use it.
+ atcommand_memo_sub(sd);
+ } else {
+ sprintf(output, "Please, enter a valid position (usage: @memo <memo_position:%d-%d>).", MIN_PORTAL_MEMO, MAX_PORTAL_MEMO);
+ clif_displaymessage(fd, output);
+ atcommand_memo_sub(sd);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_gat(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char output[200];
+ int y;
+
+ memset(output, '\0', sizeof(output));
+
+ for (y = 2; y >= -2; y--) {
+ sprintf(output, "%s (x= %d, y= %d) %02X %02X %02X %02X %02X",
+ map[sd->bl.m].name, sd->bl.x - 2, sd->bl.y + y,
+ map_getcell(sd->bl.m, sd->bl.x - 2, sd->bl.y + y),
+ map_getcell(sd->bl.m, sd->bl.x - 1, sd->bl.y + y),
+ map_getcell(sd->bl.m, sd->bl.x, sd->bl.y + y),
+ map_getcell(sd->bl.m, sd->bl.x + 1, sd->bl.y + y),
+ map_getcell(sd->bl.m, sd->bl.x + 2, sd->bl.y + y));
+ clif_displaymessage(fd, output);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_packet(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int x = 0, y = 0;
+
+ if (!message || !*message || sscanf(message, "%d %d", &x, &y) < 2) {
+ clif_displaymessage(fd, "Please, enter a status type/flag (usage: @packet <status type> <flag>).");
+ return -1;
+ }
+
+ clif_status_change(&sd->bl, x, y);
+
+ return 0;
+}
+
+/*==========================================
+ * @stpoint (Rewritten by [Yor])
+ *------------------------------------------
+ */
+int atcommand_statuspoint(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int point, new_status_point;
+
+ if (!message || !*message || (point = atoi(message)) == 0) {
+ clif_displaymessage(fd, "Please, enter a number (usage: @stpoint <number of points>).");
+ return -1;
+ }
+
+ new_status_point = (int)sd->status.status_point + point;
+ if (point > 0 && (point > 0x7FFF || new_status_point > 0x7FFF)) // fix positiv overflow
+ new_status_point = 0x7FFF;
+ else if (point < 0 && (point < -0x7FFF || new_status_point < 0)) // fix negativ overflow
+ new_status_point = 0;
+
+ if (new_status_point != (int)sd->status.status_point) {
+ sd->status.status_point = (short)new_status_point;
+ clif_updatestatus(sd, SP_STATUSPOINT);
+ clif_displaymessage(fd, msg_table[174]); // Number of status points changed!
+ } else {
+ if (point < 0)
+ clif_displaymessage(fd, msg_table[41]); // Impossible to decrease the number/value.
+ else
+ clif_displaymessage(fd, msg_table[149]); // Impossible to increase the number/value.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @skpoint (Rewritten by [Yor])
+ *------------------------------------------
+ */
+int atcommand_skillpoint(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int point, new_skill_point;
+
+ if (!message || !*message || (point = atoi(message)) == 0) {
+ clif_displaymessage(fd, "Please, enter a number (usage: @skpoint <number of points>).");
+ return -1;
+ }
+
+ new_skill_point = (int)sd->status.skill_point + point;
+ if (point > 0 && (point > 0x7FFF || new_skill_point > 0x7FFF)) // fix positiv overflow
+ new_skill_point = 0x7FFF;
+ else if (point < 0 && (point < -0x7FFF || new_skill_point < 0)) // fix negativ overflow
+ new_skill_point = 0;
+
+ if (new_skill_point != (int)sd->status.skill_point) {
+ sd->status.skill_point = (short)new_skill_point;
+ clif_updatestatus(sd, SP_SKILLPOINT);
+ clif_displaymessage(fd, msg_table[175]); // Number of skill points changed!
+ } else {
+ if (point < 0)
+ clif_displaymessage(fd, msg_table[41]); // Impossible to decrease the number/value.
+ else
+ clif_displaymessage(fd, msg_table[149]); // Impossible to increase the number/value.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @zeny (Rewritten by [Yor])
+ *------------------------------------------
+ */
+int atcommand_zeny(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int zeny, new_zeny;
+
+ if (!message || !*message || (zeny = atoi(message)) == 0) {
+ clif_displaymessage(fd, "Please, enter an amount (usage: @zeny <amount>).");
+ return -1;
+ }
+
+ new_zeny = sd->status.zeny + zeny;
+ if (zeny > 0 && (zeny > MAX_ZENY || new_zeny > MAX_ZENY)) // fix positiv overflow
+ new_zeny = MAX_ZENY;
+ else if (zeny < 0 && (zeny < -MAX_ZENY || new_zeny < 0)) // fix negativ overflow
+ new_zeny = 0;
+
+ if (new_zeny != sd->status.zeny) {
+ sd->status.zeny = new_zeny;
+ clif_updatestatus(sd, SP_ZENY);
+ clif_displaymessage(fd, msg_table[176]); // Number of zenys changed!
+ } else {
+ if (zeny < 0)
+ clif_displaymessage(fd, msg_table[41]); // Impossible to decrease the number/value.
+ else
+ clif_displaymessage(fd, msg_table[149]); // Impossible to increase the number/value.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_param(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int i, index, value = 0, new_value;
+ const char* param[] = { "@str", "@agi", "@vit", "@int", "@dex", "@luk", NULL };
+ short* status[] = {
+ &sd->status.str, &sd->status.agi, &sd->status.vit,
+ &sd->status.int_, &sd->status.dex, &sd->status.luk
+ };
+ char output[200];
+
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) {
+ sprintf(output, "Please, enter a valid value (usage: @str,@agi,@vit,@int,@dex,@luk <+/-adjustement>).");
+ clif_displaymessage(fd, output);
+ return -1;
+ }
+
+ index = -1;
+ for (i = 0; param[i] != NULL; i++) {
+ if (strcmpi(command, param[i]) == 0) {
+ index = i;
+ break;
+ }
+ }
+ if (index < 0 || index > MAX_STATUS_TYPE) { // normaly impossible...
+ sprintf(output, "Please, enter a valid value (usage: @str,@agi,@vit,@int,@dex,@luk <+/-adjustement>).");
+ clif_displaymessage(fd, output);
+ return -1;
+ }
+
+ new_value = (int)*status[index] + value;
+ if (value > 0 && (value > battle_config.max_parameter || new_value > battle_config.max_parameter)) // fix positiv overflow
+ new_value = battle_config.max_parameter;
+ else if (value < 0 && (value < -battle_config.max_parameter || new_value < 1)) // fix negativ overflow
+ new_value = 1;
+
+ if (new_value != (int)*status[index]) {
+ *status[index] = new_value;
+ clif_updatestatus(sd, SP_STR + index);
+ clif_updatestatus(sd, SP_USTR + index);
+ pc_calcstatus(sd, 0);
+ clif_displaymessage(fd, msg_table[42]); // Stat changed.
+ } else {
+ if (value < 0)
+ clif_displaymessage(fd, msg_table[41]); // Impossible to decrease the number/value.
+ else
+ clif_displaymessage(fd, msg_table[149]); // Impossible to increase the number/value.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+//** Stat all by fritz (rewritten by [Yor])
+int atcommand_stat_all(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int index, count, value = 0, new_value;
+ short* status[] = {
+ &sd->status.str, &sd->status.agi, &sd->status.vit,
+ &sd->status.int_, &sd->status.dex, &sd->status.luk
+ };
+
+ if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0)
+ value = battle_config.max_parameter;
+
+ count = 0;
+ for (index = 0; index < (int)(sizeof(status) / sizeof(status[0])); index++) {
+
+ new_value = (int)*status[index] + value;
+ if (value > 0 && (value > battle_config.max_parameter || new_value > battle_config.max_parameter)) // fix positiv overflow
+ new_value = battle_config.max_parameter;
+ else if (value < 0 && (value < -battle_config.max_parameter || new_value < 1)) // fix negativ overflow
+ new_value = 1;
+
+ if (new_value != (int)*status[index]) {
+ *status[index] = new_value;
+ clif_updatestatus(sd, SP_STR + index);
+ clif_updatestatus(sd, SP_USTR + index);
+ pc_calcstatus(sd, 0);
+ count++;
+ }
+ }
+
+ if (count > 0) // if at least 1 stat modified
+ clif_displaymessage(fd, msg_table[84]); // All stats changed!
+ else {
+ if (value < 0)
+ clif_displaymessage(fd, msg_table[177]); // Impossible to decrease a stat.
+ else
+ clif_displaymessage(fd, msg_table[178]); // Impossible to increase a stat.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_guildlevelup(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int level = 0;
+ short added_level;
+ struct guild *guild_info;
+
+ if (!message || !*message || sscanf(message, "%d", &level) < 1 || level == 0) {
+ clif_displaymessage(fd, "Please, enter a valid level (usage: @guildlvup/@guildlvlup <# of levels>).");
+ return -1;
+ }
+
+ if (sd->status.guild_id <= 0 || (guild_info = guild_search(sd->status.guild_id)) == NULL) {
+ clif_displaymessage(fd, msg_table[43]); // You're not in a guild.
+ return -1;
+ }
+ if (strcmp(sd->status.name, guild_info->master) != 0) {
+ clif_displaymessage(fd, msg_table[44]); // You're not the master of your guild.
+ return -1;
+ }
+
+ added_level = (short)level;
+ if (level > 0 && (level > MAX_GUILDLEVEL || added_level > ((short)MAX_GUILDLEVEL - guild_info->guild_lv))) // fix positiv overflow
+ added_level = (short)MAX_GUILDLEVEL - guild_info->guild_lv;
+ else if (level < 0 && (level < -MAX_GUILDLEVEL || added_level < (1 - guild_info->guild_lv))) // fix negativ overflow
+ added_level = 1 - guild_info->guild_lv;
+
+ if (added_level != 0) {
+ intif_guild_change_basicinfo(guild_info->guild_id, GBI_GUILDLV, &added_level, 2);
+ clif_displaymessage(fd, msg_table[179]); // Guild level changed.
+ } else {
+ clif_displaymessage(fd, msg_table[45]); // Guild level change failed.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_makeegg(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct item_data *item_data;
+ int id, pet_id;
+
+ if (!message || !*message) {
+ clif_displaymessage(fd, "Please, enter a monter/egg name/id (usage: @makeegg <pet_id>).");
+ return -1;
+ }
+
+ if ((item_data = itemdb_searchname(message)) != NULL) // for egg name
+ id = item_data->nameid;
+ else if ((id = mobdb_searchname(message)) == 0) // for monster name
+ id = atoi(message);
+
+ pet_id = search_petDB_index(id, PET_CLASS);
+ if (pet_id < 0)
+ pet_id = search_petDB_index(id, PET_EGG);
+ if (pet_id >= 0) {
+ sd->catch_target_class = pet_db[pet_id].class;
+ intif_create_pet(
+ sd->status.account_id, sd->status.char_id,
+ pet_db[pet_id].class, mob_db[pet_db[pet_id].class].lv,
+ pet_db[pet_id].EggID, 0, pet_db[pet_id].intimate,
+ 100, 0, 1, pet_db[pet_id].jname);
+ } else {
+ clif_displaymessage(fd, msg_table[180]); // The monter/egg name/id doesn't exist.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_hatch(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ if (sd->status.pet_id <= 0)
+ clif_sendegg(sd);
+ else {
+ clif_displaymessage(fd, msg_table[181]); // You already have a pet.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_petfriendly(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int friendly;
+ int t;
+
+ if (!message || !*message || (friendly = atoi(message)) < 0) {
+ clif_displaymessage(fd, "Please, enter a valid value (usage: @petfriendly <0-1000>).");
+ return -1;
+ }
+
+ if (sd->status.pet_id > 0 && sd->pd) {
+ if (friendly >= 0 && friendly <= 1000) {
+ if (friendly != sd->pet.intimate) {
+ t = sd->pet.intimate;
+ sd->pet.intimate = friendly;
+ clif_send_petstatus(sd);
+ if (battle_config.pet_status_support) {
+ if ((sd->pet.intimate > 0 && t <= 0) ||
+ (sd->pet.intimate <= 0 && t > 0)) {
+ if (sd->bl.prev != NULL)
+ pc_calcstatus(sd, 0);
+ else
+ pc_calcstatus(sd, 2);
+ }
+ }
+ clif_displaymessage(fd, msg_table[182]); // Pet friendly value changed!
+ } else {
+ clif_displaymessage(fd, msg_table[183]); // Pet friendly is already the good value.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[37]); // An invalid number was specified.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[184]); // Sorry, but you have no pet.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_pethungry(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int hungry;
+
+ if (!message || !*message || (hungry = atoi(message)) < 0) {
+ clif_displaymessage(fd, "Please, enter a valid number (usage: @pethungry <0-100>).");
+ return -1;
+ }
+
+ if (sd->status.pet_id > 0 && sd->pd) {
+ if (hungry >= 0 && hungry <= 100) {
+ if (hungry != sd->pet.hungry) {
+ sd->pet.hungry = hungry;
+ clif_send_petstatus(sd);
+ clif_displaymessage(fd, msg_table[185]); // Pet hungry value changed!
+ } else {
+ clif_displaymessage(fd, msg_table[186]); // Pet hungry is already the good value.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[37]); // An invalid number was specified.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[184]); // Sorry, but you have no pet.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_petrename(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ if (sd->status.pet_id > 0 && sd->pd) {
+ if (sd->pet.rename_flag != 0) {
+ sd->pet.rename_flag = 0;
+ intif_save_petdata(sd->status.account_id, &sd->pet);
+ clif_send_petstatus(sd);
+ clif_displaymessage(fd, msg_table[187]); // You can now rename your pet.
+ } else {
+ clif_displaymessage(fd, msg_table[188]); // You can already rename your pet.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[184]); // Sorry, but you have no pet.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_charpetrename(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ struct map_session_data *pl_sd;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @charpetrename <char name>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pl_sd->status.pet_id > 0 && pl_sd->pd) {
+ if (pl_sd->pet.rename_flag != 0) {
+ pl_sd->pet.rename_flag = 0;
+ intif_save_petdata(pl_sd->status.account_id, &pl_sd->pet);
+ clif_send_petstatus(pl_sd);
+ clif_displaymessage(fd, msg_table[189]); // This player can now rename his/her pet.
+ } else {
+ clif_displaymessage(fd, msg_table[190]); // This player can already rename his/her pet.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[191]); // Sorry, but this player has no pet.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int
+atcommand_recall(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ char output[200];
+ struct map_session_data *pl_sd = NULL;
+
+ nullpo_retr(-1, sd);
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @recall <char name>).");
+ return -1;
+ }
+
+ memset(character, '\0', sizeof character);
+ if(sscanf(message, "%99[^\n]", character) < 1)
+ return -1;
+ if(strncmp(sd->status.name,character,24)==0)
+ return -1;
+
+ intif_charmovereq(sd,character,1);
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can recall only lower or same level
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp somenone to your actual map.");
+ return -1;
+ }
+ if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp this player from its actual map.");
+ return -1;
+ }
+ pc_setpos(pl_sd, sd->mapname, sd->bl.x, sd->bl.y, 2);
+ sprintf(output, msg_table[46], character); // %s recalled!
+ clif_displaymessage(fd, output);
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 対象キャラクターを転職させる upper指定で転生や養子も可能
+ *------------------------------------------
+ */
+int atcommand_character_job(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ struct map_session_data* pl_sd;
+ int job = 0, upper = -1;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message) {
+ clif_displaymessage(fd, "Please, enter a job and a player name (usage: @charjob/@charjobchange <job ID> <char name>).");
+ return -1;
+ }
+
+ if (sscanf(message, "%d %d %99[^\n]", &job, &upper, character) < 3) { //upper指定してある
+ upper = -1;
+ if (sscanf(message, "%d %99[^\n]", &job, character) < 2) { //upper指定してない上に何か足りない
+ clif_displaymessage(fd, "Please, enter a job and a player name (usage: @charjob/@charjobchange <job ID> <char name>).");
+ return -1;
+ }
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can change job only to lower or same level
+ if ((job >= 0 && job < MAX_PC_CLASS)) {
+
+ // fix pecopeco display
+ if ((job != 13 && job != 21 && job != 4014 && job != 4022)) {
+ if (pc_isriding(sd)) {
+ if (pl_sd->status.class == 13)
+ pl_sd->status.class = pl_sd->view_class = 7;
+ if (pl_sd->status.class == 21)
+ pl_sd->status.class = pl_sd->view_class = 14;
+ if (pl_sd->status.class == 4014)
+ pl_sd->status.class = pl_sd->view_class = 4008;
+ if (pl_sd->status.class == 4022)
+ pl_sd->status.class = pl_sd->view_class = 4015;
+ pl_sd->status.option &= ~0x0020;
+ clif_changeoption(&pl_sd->bl);
+ pc_calcstatus(pl_sd, 0);
+ }
+ } else {
+ if (!pc_isriding(sd)) {
+ if (job == 13)
+ job = 7;
+ if (job == 21)
+ job = 14;
+ if (job == 4014)
+ job = 4008;
+ if (job == 4022)
+ job = 4015;
+ }
+ }
+
+ if (pc_jobchange(pl_sd, job, upper) == 0)
+ clif_displaymessage(fd, msg_table[48]); // Character's job changed.
+ else {
+ clif_displaymessage(fd, msg_table[192]); // Impossible to change the character's job.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[49]); // Invalid job ID.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_revive(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ struct map_session_data *pl_sd;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @revive <char name>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ pl_sd->status.hp = pl_sd->status.max_hp;
+ pc_setstand(pl_sd);
+ if (battle_config.pc_invincible_time > 0)
+ pc_setinvincibletimer(sd, battle_config.pc_invincible_time);
+ clif_updatestatus(pl_sd, SP_HP);
+ clif_updatestatus(pl_sd, SP_SP);
+ clif_resurrection(&pl_sd->bl, 1);
+ clif_displaymessage(fd, msg_table[51]); // Character revived.
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_character_stats(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ char job_jobname[100];
+ char output[200];
+ struct map_session_data *pl_sd;
+ int i;
+
+ memset(character, '\0', sizeof(character));
+ memset(job_jobname, '\0', sizeof(job_jobname));
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @charstats <char name>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ struct {
+ const char* format;
+ int value;
+ } output_table[] = {
+ { "Base Level - %d", pl_sd->status.base_level },
+ { job_jobname, pl_sd->status.job_level },
+ { "Hp - %d", pl_sd->status.hp },
+ { "MaxHp - %d", pl_sd->status.max_hp },
+ { "Sp - %d", pl_sd->status.sp },
+ { "MaxSp - %d", pl_sd->status.max_sp },
+ { "Str - %3d", pl_sd->status.str },
+ { "Agi - %3d", pl_sd->status.agi },
+ { "Vit - %3d", pl_sd->status.vit },
+ { "Int - %3d", pl_sd->status.int_ },
+ { "Dex - %3d", pl_sd->status.dex },
+ { "Luk - %3d", pl_sd->status.luk },
+ { "Zeny - %d", pl_sd->status.zeny },
+ { NULL, 0 }
+ };
+ sprintf(job_jobname, "Job - %s %s", job_name(pl_sd->status.class), "(level %d)");
+ sprintf(output, msg_table[53], pl_sd->status.name); // '%s' stats:
+ clif_displaymessage(fd, output);
+ for (i = 0; output_table[i].format != NULL; i++) {
+ sprintf(output, output_table[i].format, output_table[i].value);
+ clif_displaymessage(fd, output);
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+//** Character Stats All by fritz
+int atcommand_character_stats_all(const int fd, struct map_session_data* sd, const char* command, const char* message)
+{
+ char output[1024], gmlevel[1024];
+ int i;
+ int count;
+ struct map_session_data *pl_sd;
+
+ memset(output, '\0', sizeof(output));
+ memset(gmlevel, '\0', sizeof(gmlevel));
+
+ count = 0;
+ for(i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
+
+ if (pc_isGM(pl_sd) > 0)
+ sprintf(gmlevel, "| GM Lvl: %d", pc_isGM(pl_sd));
+ else
+ sprintf(gmlevel, " ");
+
+ sprintf(output, "Name: %s | BLvl: %d | Job: %s (Lvl: %d) | HP: %d/%d | SP: %d/%d", pl_sd->status.name, pl_sd->status.base_level, job_name(pl_sd->status.class), pl_sd->status.job_level, pl_sd->status.hp, pl_sd->status.max_hp, pl_sd->status.sp, pl_sd->status.max_sp);
+ clif_displaymessage(fd, output);
+ sprintf(output, "STR: %d | AGI: %d | VIT: %d | INT: %d | DEX: %d | LUK: %d | Zeny: %d %s", pl_sd->status.str, pl_sd->status.agi, pl_sd->status.vit, pl_sd->status.int_, pl_sd->status.dex, pl_sd->status.luk, pl_sd->status.zeny, gmlevel);
+ clif_displaymessage(fd, output);
+ clif_displaymessage(fd, "--------");
+ count++;
+ }
+ }
+
+ if (count == 0)
+ clif_displaymessage(fd, msg_table[28]); // No player found.
+ else if (count == 1)
+ clif_displaymessage(fd, msg_table[29]); // 1 player found.
+ else {
+ sprintf(output, msg_table[30], count); // %d players found.
+ clif_displaymessage(fd, output);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_character_option(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ int opt1 = 0, opt2 = 0, opt3 = 0;
+ struct map_session_data* pl_sd;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%d %d %d %99[^\n]", &opt1, &opt2, &opt3, character) < 4 || opt1 < 0 || opt2 < 0 || opt3 < 0) {
+ clif_displaymessage(fd, "Please, enter valid options and a player name (usage: @charoption <param1> <param2> <param3> <charname>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can change option only to lower or same level
+ pl_sd->opt1 = opt1;
+ pl_sd->opt2 = opt2;
+ pl_sd->status.option = opt3;
+ // fix pecopeco display
+ if (pl_sd->status.class == 13 || pl_sd->status.class == 21 || pl_sd->status.class == 4014 || pl_sd->status.class == 4022) {
+ if (!pc_isriding(pl_sd)) { // pl_sd have the new value...
+ if (pl_sd->status.class == 13)
+ pl_sd->status.class = pl_sd->view_class = 7;
+ else if (pl_sd->status.class == 21)
+ pl_sd->status.class = pl_sd->view_class = 14;
+ else if (pl_sd->status.class == 4014)
+ pl_sd->status.class = pl_sd->view_class = 4008;
+ else if (pl_sd->status.class == 4022)
+ pl_sd->status.class = pl_sd->view_class = 4015;
+ }
+ } else {
+ if (pc_isriding(pl_sd)) { // pl_sd have the new value...
+ if (pl_sd->disguise > 0) { // temporary prevention of crash caused by peco + disguise, will look into a better solution [Valaris] (code added by [Yor])
+ pl_sd->status.option &= ~0x0020;
+ } else {
+ if (pl_sd->status.class == 7)
+ pl_sd->status.class = pl_sd->view_class = 13;
+ else if (pl_sd->status.class == 14)
+ pl_sd->status.class = pl_sd->view_class = 21;
+ else if (pl_sd->status.class == 4008)
+ pl_sd->status.class = pl_sd->view_class = 4014;
+ else if (pl_sd->status.class == 4015)
+ pl_sd->status.class = pl_sd->view_class = 4022;
+ else
+ pl_sd->status.option &= ~0x0020;
+ }
+ }
+ }
+ clif_changeoption(&pl_sd->bl);
+ pc_calcstatus(pl_sd, 0);
+ clif_displaymessage(fd, msg_table[58]); // Character's options changed.
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * charchangesex command (usage: charchangesex <player_name>)
+ *------------------------------------------
+ */
+int atcommand_char_change_sex(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @charchangesex <name>).");
+ return -1;
+ }
+
+ // check player name
+ if (strlen(character) < 4) {
+ clif_displaymessage(fd, msg_table[86]); // Sorry, but a player name have at least 4 characters.
+ return -1;
+ } else if (strlen(character) > 23) {
+ clif_displaymessage(fd, msg_table[87]); // Sorry, but a player name have 23 characters maximum.
+ return -1;
+ } else {
+ chrif_char_ask_name(sd->status.account_id, character, 5, 0, 0, 0, 0, 0, 0); // type: 5 - changesex
+ clif_displaymessage(fd, msg_table[88]); // Character name sends to char-server to ask it.
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * charblock command (usage: charblock <player_name>)
+ * This command do a definitiv ban on a player
+ *------------------------------------------
+ */
+int atcommand_char_block(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @charblock/@block <name>).");
+ return -1;
+ }
+
+ // check player name
+ if (strlen(character) < 4) {
+ clif_displaymessage(fd, msg_table[86]); // Sorry, but a player name have at least 4 characters.
+ return -1;
+ } else if (strlen(character) > 23) {
+ clif_displaymessage(fd, msg_table[87]); // Sorry, but a player name have 23 characters maximum.
+ return -1;
+ } else {
+ chrif_char_ask_name(sd->status.account_id, character, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block
+ clif_displaymessage(fd, msg_table[88]); // Character name sends to char-server to ask it.
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * charban command (usage: charban <time> <player_name>)
+ * This command do a limited ban on a player
+ * Time is done as follows:
+ * Adjustment value (-1, 1, +1, etc...)
+ * Modified element:
+ * a or y: year
+ * m: month
+ * j or d: day
+ * h: hour
+ * mn: minute
+ * s: second
+ * <example> @ban +1m-2mn1s-6y test_player
+ * this example adds 1 month and 1 second, and substracts 2 minutes and 6 years at the same time.
+ *------------------------------------------
+ */
+int atcommand_char_ban(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char modif[100], character[100];
+ char * modif_p;
+ int year, month, day, hour, minute, second, value;
+
+ memset(modif, '\0', sizeof(modif));
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%s %99[^\n]", modif, character) < 2) {
+ clif_displaymessage(fd, "Please, enter ban time and a player name (usage: @charban/@ban/@banish/@charbanish <time> <name>).");
+ return -1;
+ }
+
+ modif[sizeof(modif)-1] = '\0';
+ character[sizeof(character)-1] = '\0';
+
+ modif_p = modif;
+ year = month = day = hour = minute = second = 0;
+ while (modif_p[0] != '\0') {
+ value = atoi(modif_p);
+ if (value == 0)
+ modif_p++;
+ else {
+ if (modif_p[0] == '-' || modif_p[0] == '+')
+ modif_p++;
+ while (modif_p[0] >= '0' && modif_p[0] <= '9')
+ modif_p++;
+ if (modif_p[0] == 's') {
+ second = value;
+ modif_p++;
+ } else if (modif_p[0] == 'm' && modif_p[1] == 'n') {
+ minute = value;
+ modif_p = modif_p + 2;
+ } else if (modif_p[0] == 'h') {
+ hour = value;
+ modif_p++;
+ } else if (modif_p[0] == 'd' || modif_p[0] == 'j') {
+ day = value;
+ modif_p++;
+ } else if (modif_p[0] == 'm') {
+ month = value;
+ modif_p++;
+ } else if (modif_p[0] == 'y' || modif_p[0] == 'a') {
+ year = value;
+ modif_p++;
+ } else if (modif_p[0] != '\0') {
+ modif_p++;
+ }
+ }
+ }
+ if (year == 0 && month == 0 && day == 0 && hour == 0 && minute == 0 && second == 0) {
+ clif_displaymessage(fd, msg_table[85]); // Invalid time for ban command.
+ return -1;
+ }
+
+ // check player name
+ if (strlen(character) < 4) {
+ clif_displaymessage(fd, msg_table[86]); // Sorry, but a player name have at least 4 characters.
+ return -1;
+ } else if (strlen(character) > 23) {
+ clif_displaymessage(fd, msg_table[87]); // Sorry, but a player name have 23 characters maximum.
+ return -1;
+ } else {
+ chrif_char_ask_name(sd->status.account_id, character, 2, year, month, day, hour, minute, second); // type: 2 - ban
+ clif_displaymessage(fd, msg_table[88]); // Character name sends to char-server to ask it.
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * charunblock command (usage: charunblock <player_name>)
+ *------------------------------------------
+ */
+int atcommand_char_unblock(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @charunblock <player_name>).");
+ return -1;
+ }
+
+ // check player name
+ if (strlen(character) < 4) {
+ clif_displaymessage(fd, msg_table[86]); // Sorry, but a player name have at least 4 characters.
+ return -1;
+ } else if (strlen(character) > 23) {
+ clif_displaymessage(fd, msg_table[87]); // Sorry, but a player name have 23 characters maximum.
+ return -1;
+ } else {
+ // send answer to login server via char-server
+ chrif_char_ask_name(sd->status.account_id, character, 3, 0, 0, 0, 0, 0, 0); // type: 3 - unblock
+ clif_displaymessage(fd, msg_table[88]); // Character name sends to char-server to ask it.
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * charunban command (usage: charunban <player_name>)
+ *------------------------------------------
+ */
+int atcommand_char_unban(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @charunban <player_name>).");
+ return -1;
+ }
+
+ // check player name
+ if (strlen(character) < 4) {
+ clif_displaymessage(fd, msg_table[86]); // Sorry, but a player name have at least 4 characters.
+ return -1;
+ } else if (strlen(character) > 23) {
+ clif_displaymessage(fd, msg_table[87]); // Sorry, but a player name have 23 characters maximum.
+ return -1;
+ } else {
+ // send answer to login server via char-server
+ chrif_char_ask_name(sd->status.account_id, character, 4, 0, 0, 0, 0, 0, 0); // type: 4 - unban
+ clif_displaymessage(fd, msg_table[88]); // Character name sends to char-server to ask it.
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_character_save(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char map_name[100];
+ char character[100];
+ struct map_session_data* pl_sd;
+ int x = 0, y = 0;
+ int m;
+
+ memset(map_name, '\0', sizeof(map_name));
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%99s %d %d %99[^\n]", map_name, &x, &y, character) < 4 || x < 0 || y < 0) {
+ clif_displaymessage(fd, "Please, enter a valid save point and a player name (usage: @charsave <map> <x> <y> <charname>).");
+ return -1;
+ }
+
+ if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat)
+ strcat(map_name, ".gat");
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can change save point only to lower or same gm level
+ m = map_mapname2mapid(map_name);
+ if (m < 0) {
+ clif_displaymessage(fd, msg_table[1]); // Map not found.
+ return -1;
+ } else {
+ if (m >= 0 && map[m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to set this map as a save map.");
+ return -1;
+ }
+ pc_setsavepoint(pl_sd, map_name, x, y);
+ clif_displaymessage(fd, msg_table[57]); // Character's respawn point changed.
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_night(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ int i;
+
+ if (night_flag != 1) {
+ night_flag = 1; // 0=day, 1=night [Yor]
+ for(i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
+ pl_sd->opt2 |= STATE_BLIND;
+ clif_changeoption(&pl_sd->bl);
+ clif_displaymessage(pl_sd->fd, msg_table[59]); // Night has fallen.
+ }
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[89]); // Sorry, it's already the night. Impossible to execute the command.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_day(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ int i;
+
+ if (night_flag != 0) {
+ night_flag = 0; // 0=day, 1=night [Yor]
+ for(i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
+ pl_sd->opt2 &= ~STATE_BLIND;
+ clif_changeoption(&pl_sd->bl);
+ clif_displaymessage(pl_sd->fd, msg_table[60]); // Day has arrived.
+ }
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[90]); // Sorry, it's already the day. Impossible to execute the command.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_doom(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ int i;
+
+ for(i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth && i != fd &&
+ pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can doom only lower or same gm level
+ pc_damage(NULL, pl_sd, pl_sd->status.hp + 1);
+ clif_displaymessage(pl_sd->fd, msg_table[61]); // The holy messenger has given judgement.
+ }
+ }
+ clif_displaymessage(fd, msg_table[62]); // Judgement was made.
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_doommap(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ int i;
+
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth && i != fd && sd->bl.m == pl_sd->bl.m &&
+ pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can doom only lower or same gm level
+ pc_damage(NULL, pl_sd, pl_sd->status.hp + 1);
+ clif_displaymessage(pl_sd->fd, msg_table[61]); // The holy messenger has given judgement.
+ }
+ }
+ clif_displaymessage(fd, msg_table[62]); // Judgement was made.
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static void atcommand_raise_sub(struct map_session_data* sd)
+{
+ if (sd && sd->state.auth && pc_isdead(sd)) {
+ sd->status.hp = sd->status.max_hp;
+ sd->status.sp = sd->status.max_sp;
+ pc_setstand(sd);
+ clif_updatestatus(sd, SP_HP);
+ clif_updatestatus(sd, SP_SP);
+ clif_resurrection(&sd->bl, 1);
+ clif_displaymessage(sd->fd, msg_table[63]); // Mercy has been shown.
+ }
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_raise(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int i;
+
+ for (i = 0; i < fd_max; i++) {
+ if (session[i])
+ atcommand_raise_sub(session[i]->session_data);
+ }
+ clif_displaymessage(fd, msg_table[64]); // Mercy has been granted.
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_raisemap(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ int i;
+
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth && sd->bl.m == pl_sd->bl.m)
+ atcommand_raise_sub(pl_sd);
+ }
+ clif_displaymessage(fd, msg_table[64]); // Mercy has been granted.
+
+ return 0;
+}
+
+/*==========================================
+ * atcommand_character_baselevel @charbaselvlで対象キャラのレベルを上げる
+ *------------------------------------------
+*/
+int atcommand_character_baselevel(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ char character[100];
+ int level = 0, i;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%d %99[^\n]", &level, character) < 2 || level == 0) {
+ clif_displaymessage(fd, "Please, enter a level adjustement and a player name (usage: @charbaselvl <#> <nickname>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can change base level only lower or same gm level
+
+ if (level > 0) {
+ if (pl_sd->status.base_level == battle_config.maximum_level) { // check for max level by Valaris
+ clif_displaymessage(fd, msg_table[91]); // Character's base level can't go any higher.
+ return 0;
+ } // End Addition
+ if (level > battle_config.maximum_level || level > (battle_config.maximum_level - pl_sd->status.base_level)) // fix positiv overflow
+ level = battle_config.maximum_level - pl_sd->status.base_level;
+ for (i = 1; i <= level; i++)
+ pl_sd->status.status_point += (pl_sd->status.base_level + i + 14) / 5;
+ pl_sd->status.base_level += level;
+ clif_updatestatus(pl_sd, SP_BASELEVEL);
+ clif_updatestatus(pl_sd, SP_NEXTBASEEXP);
+ clif_updatestatus(pl_sd, SP_STATUSPOINT);
+ pc_calcstatus(pl_sd, 0);
+ pc_heal(pl_sd, pl_sd->status.max_hp, pl_sd->status.max_sp);
+ clif_misceffect(&pl_sd->bl, 0);
+ clif_displaymessage(fd, msg_table[65]); // Character's base level raised.
+ } else {
+ if (pl_sd->status.base_level == 1) {
+ clif_displaymessage(fd, msg_table[193]); // Character's base level can't go any lower.
+ return -1;
+ }
+ if (level < -battle_config.maximum_level || level < (1 - pl_sd->status.base_level)) // fix negativ overflow
+ level = 1 - pl_sd->status.base_level;
+ if (pl_sd->status.status_point > 0) {
+ for (i = 0; i > level; i--)
+ pl_sd->status.status_point -= (pl_sd->status.base_level + i + 14) / 5;
+ if (pl_sd->status.status_point < 0)
+ pl_sd->status.status_point = 0;
+ clif_updatestatus(pl_sd, SP_STATUSPOINT);
+ } // to add: remove status points from stats
+ pl_sd->status.base_level += level;
+ clif_updatestatus(pl_sd, SP_BASELEVEL);
+ clif_updatestatus(pl_sd, SP_NEXTBASEEXP);
+ pc_calcstatus(pl_sd, 0);
+ clif_displaymessage(fd, msg_table[66]); // Character's base level lowered.
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0; //正常終了
+}
+
+/*==========================================
+ * atcommand_character_joblevel @charjoblvlで対象キャラのJobレベルを上げる
+ *------------------------------------------
+ */
+int atcommand_character_joblevel(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ char character[100];
+ int max_level = 50, level = 0;
+ //転生や養子の場合の元の職業を算出する
+ struct pc_base_job pl_s_class;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%d %99[^\n]", &level, character) < 2 || level == 0) {
+ clif_displaymessage(fd, "Please, enter a level adjustement and a player name (usage: @charjlvl <#> <nickname>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ pl_s_class = pc_calc_base_job(pl_sd->status.class);
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can change job level only lower or same gm level
+ if (pl_s_class.job == 0)
+ max_level -= 40;
+ if ((pl_s_class.job == 23) || (pl_s_class.upper == 1 && pl_s_class.type == 2)) //スパノビと転生職はJobレベルの最高が70
+ max_level += 20;
+
+ if (level > 0) {
+ if (pl_sd->status.job_level == max_level) {
+ clif_displaymessage(fd, msg_table[67]); // Character's job level can't go any higher.
+ return -1;
+ }
+ if (pl_sd->status.job_level + level > max_level)
+ level = max_level - pl_sd->status.job_level;
+ pl_sd->status.job_level += level;
+ clif_updatestatus(pl_sd, SP_JOBLEVEL);
+ clif_updatestatus(pl_sd, SP_NEXTJOBEXP);
+ pl_sd->status.skill_point += level;
+ clif_updatestatus(pl_sd, SP_SKILLPOINT);
+ pc_calcstatus(pl_sd, 0);
+ clif_misceffect(&pl_sd->bl, 1);
+ clif_displaymessage(fd, msg_table[68]); // character's job level raised.
+ } else {
+ if (pl_sd->status.job_level == 1) {
+ clif_displaymessage(fd, msg_table[194]); // Character's job level can't go any lower.
+ return -1;
+ }
+ if (pl_sd->status.job_level + level < 1)
+ level = 1 - pl_sd->status.job_level;
+ pl_sd->status.job_level += level;
+ clif_updatestatus(pl_sd, SP_JOBLEVEL);
+ clif_updatestatus(pl_sd, SP_NEXTJOBEXP);
+ if (pl_sd->status.skill_point > 0) {
+ pl_sd->status.skill_point += level;
+ if (pl_sd->status.skill_point < 0)
+ pl_sd->status.skill_point = 0;
+ clif_updatestatus(pl_sd, SP_SKILLPOINT);
+ } // to add: remove status points from skills
+ pc_calcstatus(pl_sd, 0);
+ clif_displaymessage(fd, msg_table[69]); // Character's job level lowered.
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_kick(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ char character[100];
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @kick <charname>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) // you can kick only lower or same gm level
+ clif_GM_kick(sd, pl_sd, 1);
+ else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_kickall(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ int i;
+
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth &&
+ pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can kick only lower or same gm level
+ if (sd->status.account_id != pl_sd->status.account_id)
+ clif_GM_kick(sd, pl_sd, 0);
+ }
+ }
+
+ clif_displaymessage(fd, msg_table[195]); // All players have been kicked!
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_allskill(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ pc_allskillup(sd); // all skills
+ sd->status.skill_point = 0; // 0 skill points
+ clif_updatestatus(sd, SP_SKILLPOINT); // update
+ clif_displaymessage(fd, msg_table[76]); // You have received all skills.
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_questskill(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int skill_id;
+
+ if (!message || !*message || (skill_id = atoi(message)) < 0) {
+ clif_displaymessage(fd, "Please, enter a quest skill number (usage: @questskill <#:0+>).");
+ return -1;
+ }
+
+ if (skill_id >= 0 && skill_id < MAX_SKILL_DB) {
+ if (skill_get_inf2(skill_id) & 0x01) {
+ if (pc_checkskill(sd, skill_id) == 0) {
+ pc_skill(sd, skill_id, 1, 0);
+ clif_displaymessage(fd, msg_table[70]); // You have learned the skill.
+ } else {
+ clif_displaymessage(fd, msg_table[196]); // You already have this quest skill.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[197]); // This skill number doesn't exist or isn't a quest skill.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[198]); // This skill number doesn't exist.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_charquestskill(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ struct map_session_data *pl_sd;
+ int skill_id = 0;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%d %99[^\n]", &skill_id, character) < 2 || skill_id < 0) {
+ clif_displaymessage(fd, "Please, enter a quest skill number and a player name (usage: @charquestskill <#:0+> <char_name>).");
+ return -1;
+ }
+
+ if (skill_id >= 0 && skill_id < MAX_SKILL_DB) {
+ if (skill_get_inf2(skill_id) & 0x01) {
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_checkskill(pl_sd, skill_id) == 0) {
+ pc_skill(pl_sd, skill_id, 1, 0);
+ clif_displaymessage(fd, msg_table[199]); // This player has learned the skill.
+ } else {
+ clif_displaymessage(fd, msg_table[200]); // This player already has this quest skill.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[197]); // This skill number doesn't exist or isn't a quest skill.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[198]); // This skill number doesn't exist.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_lostskill(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int skill_id;
+
+ if (!message || !*message || (skill_id = atoi(message)) < 0) {
+ clif_displaymessage(fd, "Please, enter a quest skill number (usage: @lostskill <#:0+>).");
+ return -1;
+ }
+
+ if (skill_id >= 0 && skill_id < MAX_SKILL) {
+ if (skill_get_inf2(skill_id) & 0x01) {
+ if (pc_checkskill(sd, skill_id) > 0) {
+ sd->status.skill[skill_id].lv = 0;
+ sd->status.skill[skill_id].flag = 0;
+ clif_skillinfoblock(sd);
+ clif_displaymessage(fd, msg_table[71]); // You have forgotten the skill.
+ } else {
+ clif_displaymessage(fd, msg_table[201]); // You don't have this quest skill.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[197]); // This skill number doesn't exist or isn't a quest skill.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[198]); // This skill number doesn't exist.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_charlostskill(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ struct map_session_data *pl_sd;
+ int skill_id = 0;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%d %99[^\n]", &skill_id, character) < 2 || skill_id < 0) {
+ clif_displaymessage(fd, "Please, enter a quest skill number and a player name (usage: @charlostskill <#:0+> <char_name>).");
+ return -1;
+ }
+
+ if (skill_id >= 0 && skill_id < MAX_SKILL) {
+ if (skill_get_inf2(skill_id) & 0x01) {
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_checkskill(pl_sd, skill_id) > 0) {
+ pl_sd->status.skill[skill_id].lv = 0;
+ pl_sd->status.skill[skill_id].flag = 0;
+ clif_skillinfoblock(pl_sd);
+ clif_displaymessage(fd, msg_table[202]); // This player has forgotten the skill.
+ } else {
+ clif_displaymessage(fd, msg_table[203]); // This player doesn't have this quest skill.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[197]); // This skill number doesn't exist or isn't a quest skill.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[198]); // This skill number doesn't exist.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_spiritball(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int number;
+
+ if (!message || !*message || (number = atoi(message)) < 0) {
+ clif_displaymessage(fd, "Please, enter a spirit ball number (usage: @spiritball <number: 0-1000>).");
+ return -1;
+ }
+
+ // set max number to avoid server/client crash (500 create big balls of several balls: no visial difference with more)
+ if (number > 500)
+ number = 500;
+
+ if (number >= 0 && number <= 0x7FFF) {
+ if (sd->spiritball != number || number > 499) {
+ if (sd->spiritball > 0)
+ pc_delspiritball(sd, sd->spiritball, 1);
+ sd->spiritball = number;
+ clif_spiritball(sd);
+ // no message, player can look the difference
+ if (number > 1000)
+ clif_displaymessage(fd, msg_table[204]); // WARNING: more than 1000 spiritballs can CRASH your server and/or client!
+ } else {
+ clif_displaymessage(fd, msg_table[205]); // You already have this number of spiritballs.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[37]); // An invalid number was specified.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_party(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char party[100];
+
+ memset(party, '\0', sizeof(party));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", party) < 1) {
+ clif_displaymessage(fd, "Please, enter a party name (usage: @party <party_name>).");
+ return -1;
+ }
+
+ party_create(sd, party);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_guild(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char guild[100];
+ int prev;
+
+ memset(guild, '\0', sizeof(guild));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", guild) < 1) {
+ clif_displaymessage(fd, "Please, enter a guild name (usage: @guild <guild_name>).");
+ return -1;
+ }
+
+ prev = battle_config.guild_emperium_check;
+ battle_config.guild_emperium_check = 0;
+ guild_create(sd, guild);
+ battle_config.guild_emperium_check = prev;
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_agitstart(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ if (agit_flag == 1) {
+ clif_displaymessage(fd, msg_table[73]); // Already it has started siege warfare.
+ return -1;
+ }
+
+ agit_flag = 1;
+ guild_agit_start();
+ clif_displaymessage(fd, msg_table[72]); // Guild siege warfare start!
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_agitend(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ if (agit_flag == 0) {
+ clif_displaymessage(fd, msg_table[75]); // Siege warfare hasn't started yet.
+ return -1;
+ }
+
+ agit_flag = 0;
+ guild_agit_end();
+ clif_displaymessage(fd, msg_table[74]); // Guild siege warfare end!
+
+ return 0;
+}
+
+/*==========================================
+ * @mapexitでマップサーバーを終了させる
+ *------------------------------------------
+ */
+int atcommand_mapexit(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ int i;
+
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
+ if (sd->status.account_id != pl_sd->status.account_id)
+ clif_GM_kick(sd, pl_sd, 0);
+ }
+ }
+ clif_GM_kick(sd, sd, 0);
+
+ runflag = 0;
+
+ return 0;
+}
+
+/*==========================================
+ * idsearch <part_of_name>: revrited by [Yor]
+ *------------------------------------------
+ */
+int atcommand_idsearch(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char item_name[100];
+ char output[200];
+ int i, match;
+ struct item_data *item;
+
+ memset(item_name, '\0', sizeof(item_name));
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%99s", item_name) < 0) {
+ clif_displaymessage(fd, "Please, enter a part of item name (usage: @idsearch <part_of_item_name>).");
+ return -1;
+ }
+
+ sprintf(output, msg_table[77], item_name); // The reference result of '%s' (name: id):
+ clif_displaymessage(fd, output);
+ match = 0;
+ for(i = 0; i < 20000; i++) {
+ if ((item = itemdb_exists(i)) != NULL && strstr(item->jname, item_name) != NULL) {
+ match++;
+ sprintf(output, msg_table[78], item->jname, item->nameid); // %s: %d
+ clif_displaymessage(fd, output);
+ }
+ }
+ sprintf(output, msg_table[79], match); // It is %d affair above.
+ clif_displaymessage(fd, output);
+
+ return 0;
+}
+
+/*==========================================
+ * Character Skill Reset
+ *------------------------------------------
+ */
+int atcommand_charskreset(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ char output[200];
+ struct map_session_data *pl_sd;
+
+ memset(character, '\0', sizeof(character));
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @charskreset <charname>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can reset skill points only lower or same gm level
+ pc_resetskill(pl_sd);
+ sprintf(output, msg_table[206], character); // '%s' skill points reseted!
+ clif_displaymessage(fd, output);
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * Character Stat Reset
+ *------------------------------------------
+ */
+int atcommand_charstreset(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ char output[200];
+ struct map_session_data *pl_sd;
+
+ memset(character, '\0', sizeof(character));
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @charstreset <charname>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can reset stats points only lower or same gm level
+ pc_resetstate(pl_sd);
+ sprintf(output, msg_table[207], character); // '%s' stats points reseted!
+ clif_displaymessage(fd, output);
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * Character Reset
+ *------------------------------------------
+ */
+int atcommand_charreset(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ char output[200];
+ struct map_session_data *pl_sd;
+
+ memset(character, '\0', sizeof(character));
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @charreset <charname>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can reset a character only for lower or same GM level
+ pc_resetstate(pl_sd);
+ pc_resetskill(pl_sd);
+ sprintf(output, msg_table[208], character); // '%s' skill and stats points reseted!
+ clif_displaymessage(fd, output);
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * Character Model by chbrules
+ *------------------------------------------
+ */
+int atcommand_charmodel(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int hair_style = 0, hair_color = 0, cloth_color = 0;
+ struct map_session_data *pl_sd;
+ char character[100];
+ char output[200];
+
+ memset(character, '\0', sizeof(character));
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%d %d %d %99[^\n]", &hair_style, &hair_color, &cloth_color, character) < 4 || hair_style < 0 || hair_color < 0 || cloth_color < 0) {
+ sprintf(output, "Please, enter a valid model and a player name (usage: @charmodel <hair ID: %d-%d> <hair color: %d-%d> <clothes color: %d-%d> <name>).",
+ MIN_HAIR_STYLE, MAX_HAIR_STYLE, MIN_HAIR_COLOR, MAX_HAIR_COLOR, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR);
+ clif_displaymessage(fd, output);
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE &&
+ hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR &&
+ cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) {
+
+ if (cloth_color != 0 &&
+ pl_sd->status.sex == 1 &&
+ (pl_sd->status.class == 12 || pl_sd->status.class == 17)) {
+ clif_displaymessage(fd, msg_table[35]); // You can't use this command with this class.
+ return -1;
+ } else {
+ pc_changelook(pl_sd, LOOK_HAIR, hair_style);
+ pc_changelook(pl_sd, LOOK_HAIR_COLOR, hair_color);
+ pc_changelook(pl_sd, LOOK_CLOTHES_COLOR, cloth_color);
+ clif_displaymessage(fd, msg_table[36]); // Appearence changed.
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[37]); // An invalid number was specified.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * Character Skill Point (Rewritten by [Yor])
+ *------------------------------------------
+ */
+int atcommand_charskpoint(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ char character[100];
+ int new_skill_point;
+ int point = 0;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%d %99[^\n]", &point, character) < 2 || point == 0) {
+ clif_displaymessage(fd, "Please, enter a number and a player name (usage: @charskpoint <amount> <name>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ new_skill_point = (int)pl_sd->status.skill_point + point;
+ if (point > 0 && (point > 0x7FFF || new_skill_point > 0x7FFF)) // fix positiv overflow
+ new_skill_point = 0x7FFF;
+ else if (point < 0 && (point < -0x7FFF || new_skill_point < 0)) // fix negativ overflow
+ new_skill_point = 0;
+ if (new_skill_point != (int)pl_sd->status.skill_point) {
+ pl_sd->status.skill_point = new_skill_point;
+ clif_updatestatus(pl_sd, SP_SKILLPOINT);
+ clif_displaymessage(fd, msg_table[209]); // Character's number of skill points changed!
+ } else {
+ if (point < 0)
+ clif_displaymessage(fd, msg_table[41]); // Impossible to decrease the number/value.
+ else
+ clif_displaymessage(fd, msg_table[149]); // Impossible to increase the number/value.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * Character Status Point (rewritten by [Yor])
+ *------------------------------------------
+ */
+int atcommand_charstpoint(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ char character[100];
+ int new_status_point;
+ int point = 0;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%d %99[^\n]", &point, character) < 2 || point == 0) {
+ clif_displaymessage(fd, "Please, enter a number and a player name (usage: @charstpoint <amount> <name>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ new_status_point = (int)pl_sd->status.status_point + point;
+ if (point > 0 && (point > 0x7FFF || new_status_point > 0x7FFF)) // fix positiv overflow
+ new_status_point = 0x7FFF;
+ else if (point < 0 && (point < -0x7FFF || new_status_point < 0)) // fix negativ overflow
+ new_status_point = 0;
+ if (new_status_point != (int)pl_sd->status.status_point) {
+ pl_sd->status.status_point = new_status_point;
+ clif_updatestatus(pl_sd, SP_STATUSPOINT);
+ clif_displaymessage(fd, msg_table[210]); // Character's number of status points changed!
+ } else {
+ if (point < 0)
+ clif_displaymessage(fd, msg_table[41]); // Impossible to decrease the number/value.
+ else
+ clif_displaymessage(fd, msg_table[149]); // Impossible to increase the number/value.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * Character Zeny Point (Rewritten by [Yor])
+ *------------------------------------------
+ */
+int atcommand_charzeny(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ char character[100];
+ int zeny = 0, new_zeny;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%d %99[^\n]", &zeny, character) < 2 || zeny == 0) {
+ clif_displaymessage(fd, "Please, enter a number and a player name (usage: @charzeny <zeny> <name>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ new_zeny = pl_sd->status.zeny + zeny;
+ if (zeny > 0 && (zeny > MAX_ZENY || new_zeny > MAX_ZENY)) // fix positiv overflow
+ new_zeny = MAX_ZENY;
+ else if (zeny < 0 && (zeny < -MAX_ZENY || new_zeny < 0)) // fix negativ overflow
+ new_zeny = 0;
+ if (new_zeny != pl_sd->status.zeny) {
+ pl_sd->status.zeny = new_zeny;
+ clif_updatestatus(pl_sd, SP_ZENY);
+ clif_displaymessage(fd, msg_table[211]); // Character's number of zenys changed!
+ } else {
+ if (zeny < 0)
+ clif_displaymessage(fd, msg_table[41]); // Impossible to decrease the number/value.
+ else
+ clif_displaymessage(fd, msg_table[149]); // Impossible to increase the number/value.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * Recall All Characters Online To Your Location
+ *------------------------------------------
+ */
+int atcommand_recallall(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ int i;
+ int count;
+ char output[200];
+
+ memset(output, '\0', sizeof(output));
+
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp somenone to your actual map.");
+ return -1;
+ }
+
+ count = 0;
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth && sd->status.account_id != pl_sd->status.account_id &&
+ pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can recall only lower or same level
+ if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd))
+ count++;
+ else
+ pc_setpos(pl_sd, sd->mapname, sd->bl.x, sd->bl.y, 2);
+ }
+ }
+
+ clif_displaymessage(fd, msg_table[92]); // All characters recalled!
+ if (count) {
+ sprintf(output, "Because you are not authorised to warp from some maps, %d player(s) have not been recalled.", count);
+ clif_displaymessage(fd, output);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * Recall online characters of a guild to your location
+ *------------------------------------------
+ */
+int atcommand_guildrecall(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ int i;
+ char guild_name[100];
+ char output[200];
+ struct guild *g;
+ int count;
+
+ memset(guild_name, '\0', sizeof(guild_name));
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", guild_name) < 1) {
+ clif_displaymessage(fd, "Please, enter a guild name/id (usage: @guildrecall <guild_name/id>).");
+ return -1;
+ }
+
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp somenone to your actual map.");
+ return -1;
+ }
+
+ if ((g = guild_searchname(guild_name)) != NULL || // name first to avoid error when name begin with a number
+ (g = guild_search(atoi(message))) != NULL) {
+ count = 0;
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth &&
+ sd->status.account_id != pl_sd->status.account_id &&
+ pl_sd->status.guild_id == g->guild_id) {
+ if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd))
+ count++;
+ else
+ pc_setpos(pl_sd, sd->mapname, sd->bl.x, sd->bl.y, 2);
+ }
+ }
+ sprintf(output, msg_table[93], g->name); // All online characters of the %s guild are near you.
+ clif_displaymessage(fd, output);
+ if (count) {
+ sprintf(output, "Because you are not authorised to warp from some maps, %d player(s) have not been recalled.", count);
+ clif_displaymessage(fd, output);
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[94]); // Incorrect name/ID, or no one from the guild is online.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * Recall online characters of a party to your location
+ *------------------------------------------
+ */
+int atcommand_partyrecall(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int i;
+ struct map_session_data *pl_sd;
+ char party_name[100];
+ char output[200];
+ struct party *p;
+ int count;
+
+ memset(party_name, '\0', sizeof(party_name));
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", party_name) < 1) {
+ clif_displaymessage(fd, "Please, enter a party name/id (usage: @partyrecall <party_name/id>).");
+ return -1;
+ }
+
+ if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
+ clif_displaymessage(fd, "You are not authorised to warp somenone to your actual map.");
+ return -1;
+ }
+
+ if ((p = party_searchname(party_name)) != NULL || // name first to avoid error when name begin with a number
+ (p = party_search(atoi(message))) != NULL) {
+ count = 0;
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth &&
+ sd->status.account_id != pl_sd->status.account_id &&
+ pl_sd->status.party_id == p->party_id) {
+ if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd))
+ count++;
+ else
+ pc_setpos(pl_sd, sd->mapname, sd->bl.x, sd->bl.y, 2);
+ }
+ }
+ sprintf(output, msg_table[95], p->name); // All online characters of the %s party are near you.
+ clif_displaymessage(fd, output);
+ if (count) {
+ sprintf(output, "Because you are not authorised to warp from some maps, %d player(s) have not been recalled.", count);
+ clif_displaymessage(fd, output);
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[96]); // Incorrect name or ID, or no one from the party is online.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_reloaditemdb(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ itemdb_reload();
+ clif_displaymessage(fd, msg_table[97]); // Item database reloaded.
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_reloadmobdb(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ mob_reload();
+ clif_displaymessage(fd, msg_table[98]); // Monster database reloaded.
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_reloadskilldb(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ skill_reload();
+ clif_displaymessage(fd, msg_table[99]); // Skill database reloaded.
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+#ifndef TXT_ONLY
+int atcommand_rehash(
+#else /* TXT_ONLY */
+int atcommand_reloadscript(
+#endif /* TXT_ONLY */
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+#ifndef TXT_ONLY
+ atcommand_broadcast( fd, sd, "@broadcast", "eAthena SQL Server is Rehashing..." );
+ atcommand_broadcast( fd, sd, "@broadcast", "You will feel a bit of lag at this point !" );
+
+ rehash( fd, sd );
+
+ atcommand_broadcast( fd, sd, "@broadcast", "Reloading NPCs..." );
+#endif /* not TXT_ONLY */
+ do_init_npc();
+ do_init_script();
+
+ npc_event_do_oninit();
+
+ clif_displaymessage(fd, msg_table[100]); // Scripts reloaded.
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_reloadgmdb( // by [Yor]
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ chrif_reloadGMdb();
+
+ clif_displaymessage(fd, msg_table[101]); // Login-server asked to reload GM accounts and their level.
+
+ return 0;
+}
+
+/*==========================================
+ * @mapinfo <map name> [0-3] by MC_Cameri
+ * => Shows information about the map [map name]
+ * 0 = no additional information
+ * 1 = Show users in that map and their location
+ * 2 = Shows NPCs in that map
+ * 3 = Shows the shops/chats in that map (not implemented)
+ *------------------------------------------
+ */
+int atcommand_mapinfo(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ struct npc_data *nd = NULL;
+ struct chat_data *cd = NULL;
+ char output[200], map_name[100];
+ char direction[12];
+ int m_id, i, chat_num, list = 0;
+
+ memset(output, '\0', sizeof(output));
+ memset(map_name, '\0', sizeof(map_name));
+ memset(direction, '\0', sizeof(direction));
+
+ sscanf(message, "%d %99[^\n]", &list, map_name);
+
+ if (list < 0 || list > 3) {
+ clif_displaymessage(fd, "Please, enter at least a valid list number (usage: @mapinfo <0-3> [map]).");
+ return -1;
+ }
+
+ if (map_name[0] == '\0')
+ strcpy(map_name, sd->mapname);
+ if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat)
+ strcat(map_name, ".gat");
+
+ if ((m_id = map_mapname2mapid(map_name)) < 0) {
+ clif_displaymessage(fd, msg_table[1]); // Map not found.
+ return -1;
+ }
+
+ clif_displaymessage(fd, "------ Map Info ------");
+ sprintf(output, "Map Name: %s", map_name);
+ clif_displaymessage(fd, output);
+ sprintf(output, "Players In Map: %d", map[m_id].users);
+ clif_displaymessage(fd, output);
+ sprintf(output, "NPCs In Map: %d", map[m_id].npc_num);
+ clif_displaymessage(fd, output);
+ chat_num = 0;
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth &&
+ (cd = (struct chat_data*)map_id2bl(pl_sd->chatID))) {
+ chat_num++;
+ }
+ }
+ sprintf(output, "Chats In Map: %d", chat_num);
+ clif_displaymessage(fd, output);
+ clif_displaymessage(fd, "------ Map Flags ------");
+ sprintf(output, "Player vs Player: %s | No Guild: %s | No Party: %s",
+ (map[m_id].flag.pvp) ? "True" : "False",
+ (map[m_id].flag.pvp_noguild) ? "True" : "False",
+ (map[m_id].flag.pvp_noparty) ? "True" : "False");
+ clif_displaymessage(fd, output);
+ sprintf(output, "Guild vs Guild: %s | No Party: %s", (map[m_id].flag.gvg) ? "True" : "False", (map[m_id].flag.gvg_noparty) ? "True" : "False");
+ clif_displaymessage(fd, output);
+ sprintf(output, "No Dead Branch: %s", (map[m_id].flag.nobranch) ? "True" : "False");
+ clif_displaymessage(fd, output);
+ sprintf(output, "No Memo: %s", (map[m_id].flag.nomemo) ? "True" : "False");
+ clif_displaymessage(fd, output);
+ sprintf(output, "No Penalty: %s", (map[m_id].flag.nopenalty) ? "True" : "False");
+ clif_displaymessage(fd, output);
+ sprintf(output, "No Return: %s", (map[m_id].flag.noreturn) ? "True" : "False");
+ clif_displaymessage(fd, output);
+ sprintf(output, "No Save: %s", (map[m_id].flag.nosave) ? "True" : "False");
+ clif_displaymessage(fd, output);
+ sprintf(output, "No Teleport: %s", (map[m_id].flag.noteleport) ? "True" : "False");
+ clif_displaymessage(fd, output);
+ sprintf(output, "No Monster Teleport: %s", (map[m_id].flag.monster_noteleport) ? "True" : "False");
+ clif_displaymessage(fd, output);
+ sprintf(output, "No Zeny Penalty: %s", (map[m_id].flag.nozenypenalty) ? "True" : "False");
+ clif_displaymessage(fd, output);
+
+ switch (list) {
+ case 0:
+ // Do nothing. It's list 0, no additional display.
+ break;
+ case 1:
+ clif_displaymessage(fd, "----- Players in Map -----");
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth && strcmp(pl_sd->mapname, map_name) == 0) {
+ sprintf(output, "Player '%s' (session #%d) | Location: %d,%d",
+ pl_sd->status.name, i, pl_sd->bl.x, pl_sd->bl.y);
+ clif_displaymessage(fd, output);
+ }
+ }
+ break;
+ case 2:
+ clif_displaymessage(fd, "----- NPCs in Map -----");
+ for (i = 0; i < map[m_id].npc_num;) {
+ nd = map[m_id].npc[i];
+ switch(nd->dir) {
+ case 0: strcpy(direction, "North"); break;
+ case 1: strcpy(direction, "North West"); break;
+ case 2: strcpy(direction, "West"); break;
+ case 3: strcpy(direction, "South West"); break;
+ case 4: strcpy(direction, "South"); break;
+ case 5: strcpy(direction, "South East"); break;
+ case 6: strcpy(direction, "East"); break;
+ case 7: strcpy(direction, "North East"); break;
+ case 9: strcpy(direction, "North"); break;
+ default: strcpy(direction, "Unknown"); break;
+ }
+ sprintf(output, "NPC %d: %s | Direction: %s | Sprite: %d | Location: %d %d",
+ ++i, nd->name, direction, nd->class, nd->bl.x, nd->bl.y);
+ clif_displaymessage(fd, output);
+ }
+ break;
+ case 3:
+ clif_displaymessage(fd, "----- Chats in Map -----");
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth &&
+ (cd = (struct chat_data*)map_id2bl(pl_sd->chatID)) &&
+ strcmp(pl_sd->mapname, map_name) == 0 &&
+ cd->usersd[0] == pl_sd) {
+ sprintf(output, "Chat %d: %s | Player: %s | Location: %d %d",
+ i, cd->title, pl_sd->status.name, cd->bl.x, cd->bl.y);
+ clif_displaymessage(fd, output);
+ sprintf(output, " Users: %d/%d | Password: %s | Public: %s",
+ cd->users, cd->limit, cd->pass, (cd->pub) ? "Yes" : "No");
+ clif_displaymessage(fd, output);
+ }
+ }
+ break;
+ default: // normally impossible to arrive here
+ clif_displaymessage(fd, "Please, enter at least a valid list number (usage: @mapinfo <0-3> [map]).");
+ return -1;
+ break;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_mount_peco(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ if (sd->disguise > 0) { // temporary prevention of crash caused by peco + disguise, will look into a better solution [Valaris]
+ clif_displaymessage(fd, msg_table[212]); // Cannot mount a Peco while in disguise.
+ return -1;
+ }
+
+ if (!pc_isriding(sd)) { // if actually no peco
+ if (sd->status.class == 7 || sd->status.class == 14 || sd->status.class == 4008 || sd->status.class == 4015) {
+ if (sd->status.class == 7)
+ sd->status.class = sd->view_class = 13;
+ else if (sd->status.class == 14)
+ sd->status.class = sd->view_class = 21;
+ else if (sd->status.class == 4008)
+ sd->status.class = sd->view_class = 4014;
+ else if (sd->status.class == 4015)
+ sd->status.class = sd->view_class = 4022;
+ pc_setoption(sd, sd->status.option | 0x0020);
+ clif_displaymessage(fd, msg_table[102]); // Mounted Peco.
+ } else {
+ clif_displaymessage(fd, msg_table[213]); // You can not mount a peco with your job.
+ return -1;
+ }
+ } else {
+ if (sd->status.class == 13)
+ sd->status.class = sd->view_class = 7;
+ else if (sd->status.class == 21)
+ sd->status.class = sd->view_class = 14;
+ else if (sd->status.class == 4014)
+ sd->status.class = sd->view_class = 4008;
+ else if (sd->status.class == 4022)
+ sd->status.class = sd->view_class = 4015;
+ pc_setoption(sd, sd->status.option & ~0x0020);
+ clif_displaymessage(fd, msg_table[214]); // Unmounted Peco.
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_char_mount_peco(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ struct map_session_data *pl_sd;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @charmountpeco <char_name>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pl_sd->disguise > 0) { // temporary prevention of crash caused by peco + disguise, will look into a better solution [Valaris]
+ clif_displaymessage(fd, msg_table[215]); // This player cannot mount a Peco while in disguise.
+ return -1;
+ }
+
+ if (!pc_isriding(pl_sd)) { // if actually no peco
+ if (pl_sd->status.class == 7 || pl_sd->status.class == 14 || pl_sd->status.class == 4008 || pl_sd->status.class == 4015) {
+ if (pl_sd->status.class == 7)
+ pl_sd->status.class = pl_sd->view_class = 13;
+ else if (pl_sd->status.class == 14)
+ pl_sd->status.class = pl_sd->view_class = 21;
+ else if (pl_sd->status.class == 4008)
+ pl_sd->status.class = pl_sd->view_class = 4014;
+ else if (pl_sd->status.class == 4015)
+ pl_sd->status.class = pl_sd->view_class = 4022;
+ pc_setoption(pl_sd, pl_sd->status.option | 0x0020);
+ clif_displaymessage(fd, msg_table[216]); // Now, this player mounts a peco.
+ } else {
+ clif_displaymessage(fd, msg_table[217]); // This player can not mount a peco with his/her job.
+ return -1;
+ }
+ } else {
+ if (pl_sd->status.class == 13)
+ pl_sd->status.class = pl_sd->view_class = 7;
+ else if (pl_sd->status.class == 21)
+ pl_sd->status.class = pl_sd->view_class = 14;
+ else if (pl_sd->status.class == 4014)
+ pl_sd->status.class = pl_sd->view_class = 4008;
+ else if (pl_sd->status.class == 4022)
+ pl_sd->status.class = pl_sd->view_class = 4015;
+ pc_setoption(pl_sd, pl_sd->status.option & ~0x0020);
+ clif_displaymessage(fd, msg_table[218]); // Now, this player has not more peco.
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *Spy Commands by Syrus22
+ *------------------------------------------
+ */
+int atcommand_guildspy(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char guild_name[100];
+ char output[200];
+ struct guild *g;
+
+ memset(guild_name, '\0', sizeof(guild_name));
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", guild_name) < 1) {
+ clif_displaymessage(fd, "Please, enter a guild name/id (usage: @guildspy <guild_name/id>).");
+ return -1;
+ }
+
+ if ((g = guild_searchname(guild_name)) != NULL || // name first to avoid error when name begin with a number
+ (g = guild_search(atoi(message))) != NULL) {
+ if (sd->guildspy == g->guild_id) {
+ sd->guildspy = 0;
+ sprintf(output, msg_table[103], g->name); // No longer spying on the %s guild.
+ clif_displaymessage(fd, output);
+ } else {
+ sd->guildspy = g->guild_id;
+ sprintf(output, msg_table[104], g->name); // Spying on the %s guild.
+ clif_displaymessage(fd, output);
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[94]); // Incorrect name/ID, or no one from the guild is online.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_partyspy(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char party_name[100];
+ char output[200];
+ struct party *p;
+
+ memset(party_name, '\0', sizeof(party_name));
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", party_name) < 1) {
+ clif_displaymessage(fd, "Please, enter a party name/id (usage: @partyspy <party_name/id>).");
+ return -1;
+ }
+
+ if ((p = party_searchname(party_name)) != NULL || // name first to avoid error when name begin with a number
+ (p = party_search(atoi(message))) != NULL) {
+ if (sd->partyspy == p->party_id) {
+ sd->partyspy = 0;
+ sprintf(output, msg_table[105], p->name); // No longer spying on the %s party.
+ clif_displaymessage(fd, output);
+ } else {
+ sd->partyspy = p->party_id;
+ sprintf(output, msg_table[106], p->name); // Spying on the %s party.
+ clif_displaymessage(fd, output);
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[96]); // Incorrect name or ID, or no one from the party is online.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @repairall [Valaris]
+ *------------------------------------------
+ */
+int atcommand_repairall(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int count, i;
+
+ count = 0;
+ for (i = 0; i < MAX_INVENTORY; i++) {
+ if (sd->status.inventory[i].nameid && sd->status.inventory[i].attribute == 1) {
+ sd->status.inventory[i].attribute = 0;
+ clif_produceeffect(sd, 0, sd->status.inventory[i].nameid);
+ count++;
+ }
+ }
+
+ if (count > 0) {
+ clif_misceffect(&sd->bl, 3);
+ clif_equiplist(sd);
+ clif_displaymessage(fd, msg_table[107]); // All items have been repaired.
+ } else {
+ clif_displaymessage(fd, msg_table[108]); // No item need to be repaired.
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Removed @nuke for now in favor of alchemist marine sphere skill [Valaris]
+int atcommand_nuke(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ struct map_session_data *pl_sd;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @nuke <char name>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can kill only lower or same GM level
+ skill_castend_damage_id(&pl_sd->bl, &pl_sd->bl, NPC_SELFDESTRUCTION, 99, gettick(), 0);
+ clif_displaymessage(fd, msg_table[109]); // Player has been nuked!
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+*/
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_enablenpc(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char NPCname[100];
+
+ memset(NPCname, '\0', sizeof(NPCname));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", NPCname) < 1) {
+ clif_displaymessage(fd, "Please, enter a NPC name (usage: @npcon <NPC_name>).");
+ return -1;
+ }
+
+ if (npc_name2id(NPCname) != NULL) {
+ npc_enable(NPCname, 1);
+ clif_displaymessage(fd, msg_table[110]); // Npc Enabled.
+ } else {
+ clif_displaymessage(fd, msg_table[111]); // This NPC doesn't exist.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int atcommand_disablenpc(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char NPCname[100];
+
+ memset(NPCname, '\0', sizeof(NPCname));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", NPCname) < 1) {
+ clif_displaymessage(fd, "Please, enter a NPC name (usage: @npcoff <NPC_name>).");
+ return -1;
+ }
+
+ if (npc_name2id(NPCname) != NULL) {
+ npc_enable(NPCname, 0);
+ clif_displaymessage(fd, msg_table[112]); // Npc Disabled.
+ } else {
+ clif_displaymessage(fd, msg_table[111]); // This NPC doesn't exist.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * time in txt for time command (by [Yor])
+ *------------------------------------------
+ */
+char * txt_time(unsigned int duration) {
+ int days, hours, minutes, seconds;
+ char temp[256];
+ static char temp1[256];
+
+ memset(temp, '\0', sizeof(temp));
+ memset(temp1, '\0', sizeof(temp1));
+
+ if (duration < 0)
+ duration = 0;
+
+ days = duration / (60 * 60 * 24);
+ duration = duration - (60 * 60 * 24 * days);
+ hours = duration / (60 * 60);
+ duration = duration - (60 * 60 * hours);
+ minutes = duration / 60;
+ seconds = duration - (60 * minutes);
+
+ if (days < 2)
+ sprintf(temp, msg_table[219], days); // %d day
+ else
+ sprintf(temp, msg_table[220], days); // %d days
+ if (hours < 2)
+ sprintf(temp1, msg_table[221], temp, hours); // %s %d hour
+ else
+ sprintf(temp1, msg_table[222], temp, hours); // %s %d hours
+ if (minutes < 2)
+ sprintf(temp, msg_table[223], temp1, minutes); // %s %d minute
+ else
+ sprintf(temp, msg_table[224], temp1, minutes); // %s %d minutes
+ if (seconds < 2)
+ sprintf(temp1, msg_table[225], temp, seconds); // %s and %d second
+ else
+ sprintf(temp1, msg_table[226], temp, seconds); // %s and %d seconds
+
+ return temp1;
+}
+
+/*==========================================
+ * @time/@date/@server_date/@serverdate/@server_time/@servertime: Display the date/time of the server (by [Yor]
+ * Calculation management of GM modification (@day/@night GM commands) is done
+ *------------------------------------------
+ */
+int atcommand_servertime(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct TimerData * timer_data;
+ struct TimerData * timer_data2;
+ time_t time_server; // variable for number of seconds (used with time() function)
+ struct tm *datetime; // variable for time in structure ->tm_mday, ->tm_sec, ...
+ char temp[256];
+
+ memset(temp, '\0', sizeof(temp));
+
+ time(&time_server); // get time in seconds since 1/1/1970
+ datetime = localtime(&time_server); // convert seconds in structure
+ // like sprintf, but only for date/time (Sunday, November 02 2003 15:12:52)
+ strftime(temp, sizeof(temp)-1, msg_table[230], datetime); // Server time (normal time): %A, %B %d %Y %X.
+ clif_displaymessage(fd, temp);
+
+ if (battle_config.night_duration == 0 && battle_config.day_duration == 0) {
+ if (night_flag == 0)
+ clif_displaymessage(fd, msg_table[231]); // Game time: The game is in permanent daylight.
+ else
+ clif_displaymessage(fd, msg_table[232]); // Game time: The game is in permanent night.
+ } else if (battle_config.night_duration == 0)
+ if (night_flag == 1) { // we start with night
+ timer_data = get_timer(day_timer_tid);
+ sprintf(temp, msg_table[233], txt_time((timer_data->tick - gettick()) / 1000)); // Game time: The game is actualy in night for %s.
+ clif_displaymessage(fd, temp);
+ clif_displaymessage(fd, msg_table[234]); // Game time: After, the game will be in permanent daylight.
+ } else
+ clif_displaymessage(fd, msg_table[231]); // Game time: The game is in permanent daylight.
+ else if (battle_config.day_duration == 0)
+ if (night_flag == 0) { // we start with day
+ timer_data = get_timer(night_timer_tid);
+ sprintf(temp, msg_table[235], txt_time((timer_data->tick - gettick()) / 1000)); // Game time: The game is actualy in daylight for %s.
+ clif_displaymessage(fd, temp);
+ clif_displaymessage(fd, msg_table[236]); // Game time: After, the game will be in permanent night.
+ } else
+ clif_displaymessage(fd, msg_table[232]); // Game time: The game is in permanent night.
+ else {
+ if (night_flag == 0) {
+ timer_data = get_timer(night_timer_tid);
+ timer_data2 = get_timer(day_timer_tid);
+ sprintf(temp, msg_table[235], txt_time((timer_data->tick - gettick()) / 1000)); // Game time: The game is actualy in daylight for %s.
+ clif_displaymessage(fd, temp);
+ if (timer_data->tick > timer_data2->tick)
+ sprintf(temp, msg_table[237], txt_time((timer_data->interval - abs(timer_data->tick - timer_data2->tick)) / 1000)); // Game time: After, the game will be in night for %s.
+ else
+ sprintf(temp, msg_table[237], txt_time(abs(timer_data->tick - timer_data2->tick) / 1000)); // Game time: After, the game will be in night for %s.
+ clif_displaymessage(fd, temp);
+ sprintf(temp, msg_table[238], txt_time(timer_data->interval / 1000)); // Game time: A day cycle has a normal duration of %s.
+ clif_displaymessage(fd, temp);
+ } else {
+ timer_data = get_timer(day_timer_tid);
+ timer_data2 = get_timer(night_timer_tid);
+ sprintf(temp, msg_table[233], txt_time((timer_data->tick - gettick()) / 1000)); // Game time: The game is actualy in night for %s.
+ clif_displaymessage(fd, temp);
+ if (timer_data->tick > timer_data2->tick)
+ sprintf(temp, msg_table[239], txt_time((timer_data->interval - abs(timer_data->tick - timer_data2->tick)) / 1000)); // Game time: After, the game will be in daylight for %s.
+ else
+ sprintf(temp, msg_table[239], txt_time(abs(timer_data->tick - timer_data2->tick) / 1000)); // Game time: After, the game will be in daylight for %s.
+ clif_displaymessage(fd, temp);
+ sprintf(temp, msg_table[238], txt_time(timer_data->interval / 1000)); // Game time: A day cycle has a normal duration of %s.
+ clif_displaymessage(fd, temp);
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @chardelitem <item_name_or_ID> <quantity> <player> (by [Yor]
+ * removes <quantity> item from a character
+ * item can be equiped or not.
+ * Inspired from a old command created by RoVeRT
+ *------------------------------------------
+ */
+int atcommand_chardelitem(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ char character[100];
+ char item_name[100];
+ int i, number = 0, item_id, item_position, count;
+ char output[200];
+ struct item_data *item_data;
+
+ memset(character, '\0', sizeof(character));
+ memset(item_name, '\0', sizeof(item_name));
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message || sscanf(message, "%s %d %99[^\n]", item_name, &number, character) < 3 || number < 1) {
+ clif_displaymessage(fd, "Please, enter an item name/id, a quantity and a player name (usage: @chardelitem <item_name_or_ID> <quantity> <player>).");
+ return -1;
+ }
+
+ item_id = 0;
+ if ((item_data = itemdb_searchname(item_name)) != NULL ||
+ (item_data = itemdb_exists(atoi(item_name))) != NULL)
+ item_id = item_data->nameid;
+
+ if (item_id > 500) {
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can kill only lower or same level
+ item_position = pc_search_inventory(pl_sd, item_id);
+ if (item_position >= 0) {
+ count = 0;
+ for(i = 0; i < number && item_position >= 0; i++) {
+ pc_delitem(pl_sd, item_position, 1, 0);
+ count++;
+ item_position = pc_search_inventory(pl_sd, item_id); // for next loop
+ }
+ sprintf(output, msg_table[113], count); // %d item(s) removed by a GM.
+ clif_displaymessage(pl_sd->fd, output);
+ if (number == count)
+ sprintf(output, msg_table[114], count); // %d item(s) removed from the player.
+ else
+ sprintf(output, msg_table[115], count, count, number); // %d item(s) removed. Player had only %d on %d items.
+ clif_displaymessage(fd, output);
+ } else {
+ clif_displaymessage(fd, msg_table[116]); // Character does not have the item.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[19]); // Invalid item ID or name.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @jail <char_name> by [Yor]
+ * Special warp! No check with nowarp and nowarpto flag
+ *------------------------------------------
+ */
+int atcommand_jail(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ struct map_session_data *pl_sd;
+ int x, y;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @jail <char_name>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can jail only lower or same GM
+ switch(rand() % 2) {
+ case 0:
+ x = 24;
+ y = 75;
+ break;
+ default:
+ x = 49;
+ y = 75;
+ break;
+ }
+ if (pc_setpos(pl_sd, "sec_pri.gat", x, y, 3) == 0) {
+ pc_setsavepoint(pl_sd, "sec_pri.gat", x, y); // Save Char Respawn Point in the jail room [Lupus]
+ clif_displaymessage(pl_sd->fd, msg_table[117]); // GM has send you in jails.
+ clif_displaymessage(fd, msg_table[118]); // Player warped in jails.
+ } else {
+ clif_displaymessage(fd, msg_table[1]); // Map not found.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @unjail/@discharge <char_name> by [Yor]
+ * Special warp! No check with nowarp and nowarpto flag
+ *------------------------------------------
+ */
+int atcommand_unjail(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ struct map_session_data *pl_sd;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @unjail/@discharge <char_name>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can jail only lower or same GM
+ if (pl_sd->bl.m != map_mapname2mapid("sec_pri.gat")) {
+ clif_displaymessage(fd, msg_table[119]); // This player is not in jails.
+ return -1;
+ } else if (pc_setpos(pl_sd, "prontera.gat", 156, 191, 3) == 0) {
+ pc_setsavepoint(pl_sd, "prontera.gat", 156, 191); // Save char respawn point in Prontera
+ clif_displaymessage(pl_sd->fd, msg_table[120]); // GM has discharge you.
+ clif_displaymessage(fd, msg_table[121]); // Player warped to Prontera.
+ } else {
+ clif_displaymessage(fd, msg_table[1]); // Map not found.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @disguise <mob_id> by [Valaris] (simplified by [Yor])
+ *------------------------------------------
+ */
+int atcommand_disguise(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int mob_id;
+
+ if (!message || !*message) {
+ clif_displaymessage(fd, "Please, enter a Monster/NPC name/id (usage: @disguise <monster_name_or_monster_ID>).");
+ return -1;
+ }
+
+ if ((mob_id = mobdb_searchname(message)) == 0) // check name first (to avoid possible name begining by a number)
+ mob_id = atoi(message);
+
+ if ((mob_id >= 46 && mob_id <= 125) || (mob_id >= 700 && mob_id <= 718) || // NPC
+ (mob_id >= 721 && mob_id <= 755) || (mob_id >= 757 && mob_id <= 811) || // NPC
+ (mob_id >= 813 && mob_id <= 834) || // NPC
+ (mob_id > 1000 && mob_id < 1521)) { // monsters
+ if (pc_isriding(sd)) { // temporary prevention of crash caused by peco + disguise, will look into a better solution [Valaris]
+ clif_displaymessage(fd, msg_table[227]); // Cannot wear disguise while riding a Peco.
+ return -1;
+ }
+ sd->disguiseflag = 1; // set to override items with disguise script [Valaris]
+ sd->disguise = mob_id;
+ pc_setpos(sd, sd->mapname, sd->bl.x, sd->bl.y, 3);
+ clif_displaymessage(fd, msg_table[122]); // Disguise applied.
+ } else {
+ clif_displaymessage(fd, msg_table[123]); // Monster/NPC name/id hasn't been found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @undisguise by [Yor]
+ *------------------------------------------
+ */
+int atcommand_undisguise(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ if (sd->disguise) {
+ clif_clearchar(&sd->bl, 9);
+ sd->disguise = 0;
+ pc_setpos(sd, sd->mapname, sd->bl.x, sd->bl.y, 3);
+ clif_displaymessage(fd, msg_table[124]); // Undisguise applied.
+ } else {
+ clif_displaymessage(fd, msg_table[125]); // You're not disguised.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @broadcast by [Valaris]
+ *------------------------------------------
+ */
+int atcommand_broadcast(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char output[200];
+
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message) {
+ clif_displaymessage(fd, "Please, enter a message (usage: @broadcast <message>).");
+ return -1;
+ }
+
+ sprintf(output, "%s : %s", sd->status.name, message);
+ intif_GMmessage(output, strlen(output) + 1, 0);
+
+ return 0;
+}
+
+/*==========================================
+ * @localbroadcast by [Valaris]
+ *------------------------------------------
+ */
+int atcommand_localbroadcast(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char output[200];
+
+ memset(output, '\0', sizeof(output));
+
+ if (!message || !*message) {
+ clif_displaymessage(fd, "Please, enter a message (usage: @localbroadcast <message>).");
+ return -1;
+ }
+
+ sprintf(output, "%s : %s", sd->status.name, message);
+
+ clif_GMmessage(&sd->bl, output, strlen(output) + 1, 1); // 1: ALL_SAMEMAP
+
+ return 0;
+}
+
+/*==========================================
+ * @chardisguise <mob_id> <character> by Kalaspuff (based off Valaris' and Yor's work)
+ *------------------------------------------
+ */
+int atcommand_chardisguise(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int mob_id;
+ char character[100];
+ char mob_name[100];
+ struct map_session_data* pl_sd;
+
+ memset(character, '\0', sizeof(character));
+ memset(mob_name, '\0', sizeof(mob_name));
+
+ if (!message || !*message || sscanf(message, "%s %99[^\n]", mob_name, character) < 2) {
+ clif_displaymessage(fd, "Please, enter a Monster/NPC name/id and a player name (usage: @chardisguise <monster_name_or_monster_ID> <char name>).");
+ return -1;
+ }
+
+ if ((mob_id = mobdb_searchname(mob_name)) == 0) // check name first (to avoid possible name begining by a number)
+ mob_id = atoi(mob_name);
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can disguise only lower or same level
+ if ((mob_id >= 46 && mob_id <= 125) || (mob_id >= 700 && mob_id <= 718) || // NPC
+ (mob_id >= 721 && mob_id <= 755) || (mob_id >= 757 && mob_id <= 811) || // NPC
+ (mob_id >= 813 && mob_id <= 834) || // NPC
+ (mob_id > 1000 && mob_id < 1521)) { // monsters
+ if (pc_isriding(pl_sd)) { // temporary prevention of crash caused by peco + disguise, will look into a better solution [Valaris]
+ clif_displaymessage(fd, msg_table[228]); // Character cannot wear disguise while riding a Peco.
+ return -1;
+ }
+ pl_sd->disguiseflag = 1; // set to override items with disguise script [Valaris]
+ pl_sd->disguise = mob_id;
+ pc_setpos(pl_sd, pl_sd->mapname, pl_sd->bl.x, pl_sd->bl.y, 3);
+ clif_displaymessage(fd, msg_table[140]); // Character's disguise applied.
+ } else {
+ clif_displaymessage(fd, msg_table[123]); // Monster/NPC name/id hasn't been found.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @charundisguise <character> by Kalaspuff (based off Yor's work)
+ *------------------------------------------
+ */
+int atcommand_charundisguise(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ struct map_session_data* pl_sd;
+
+ memset(character, '\0', sizeof(character));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @charundisguise <char name>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can undisguise only lower or same level
+ if (pl_sd->disguise) {
+ clif_clearchar(&pl_sd->bl, 9);
+ pl_sd->disguise = 0;
+ pc_setpos(pl_sd, pl_sd->mapname, pl_sd->bl.x, pl_sd->bl.y, 3);
+ clif_displaymessage(fd, msg_table[141]); // Character's undisguise applied.
+ } else {
+ clif_displaymessage(fd, msg_table[142]); // Character is not disguised.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @email <actual@email> <new@email> by [Yor]
+ *------------------------------------------
+ */
+int atcommand_email(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char actual_email[100];
+ char new_email[100];
+
+ memset(actual_email, '\0', sizeof(actual_email));
+ memset(new_email, '\0', sizeof(new_email));
+
+ if (!message || !*message || sscanf(message, "%99s %99s", actual_email, new_email) < 2) {
+ clif_displaymessage(fd, "Please enter 2 emails (usage: @email <actual@email> <new@email>).");
+ return -1;
+ }
+
+ if (e_mail_check(actual_email) == 0) {
+ clif_displaymessage(fd, msg_table[144]); // Invalid actual email. If you have default e-mail, give a@a.com.
+ return -1;
+ } else if (e_mail_check(new_email) == 0) {
+ clif_displaymessage(fd, msg_table[145]); // Invalid new email. Please enter a real e-mail.
+ return -1;
+ } else if (strcmpi(new_email, "a@a.com") == 0) {
+ clif_displaymessage(fd, msg_table[146]); // New email must be a real e-mail.
+ return -1;
+ } else if (strcmpi(actual_email, new_email) == 0) {
+ clif_displaymessage(fd, msg_table[147]); // New email must be different of the actual e-mail.
+ return -1;
+ } else {
+ chrif_changeemail(sd->status.account_id, actual_email, new_email);
+ clif_displaymessage(fd, msg_table[148]); // Information sended to login-server via char-server.
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *@effect
+ *------------------------------------------
+ */
+int atcommand_effect(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ int type = 0, flag = 0, i;
+
+ if (!message || !*message || sscanf(message, "%d %d", &type,&flag) < 2) {
+ clif_displaymessage(fd, "Please, enter at least a option (usage: @effect <type+>).");
+ return -1;
+ }
+ if(flag <=0){
+ clif_specialeffect(&sd->bl, type, flag);
+ clif_displaymessage(fd, msg_table[229]); // Your effect has changed.
+ }
+ else{
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
+ clif_specialeffect(&pl_sd->bl, type, flag);
+ clif_displaymessage(pl_sd->fd, msg_table[229]); // Your effect has changed.
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @charitemlist <character>: Displays the list of a player's items.
+ *------------------------------------------
+ */
+int
+atcommand_character_item_list(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ struct item_data *item_data, *item_temp;
+ int i, j, equip, count, counter, counter2;
+ char character[100], output[200], equipstr[100], outputtmp[200];
+
+ memset(character, '\0', sizeof(character));
+ memset(output, '\0', sizeof(output));
+ memset(equipstr, '\0', sizeof(equipstr));
+ memset(outputtmp, '\0', sizeof(outputtmp));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @charitemlist <char name>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can look items only lower or same level
+ counter = 0;
+ count = 0;
+ for (i = 0; i < MAX_INVENTORY; i++) {
+ if (pl_sd->status.inventory[i].nameid > 0 && (item_data = itemdb_search(pl_sd->status.inventory[i].nameid)) != NULL) {
+ counter = counter + pl_sd->status.inventory[i].amount;
+ count++;
+ if (count == 1) {
+ sprintf(output, "------ Items list of '%s' ------", pl_sd->status.name);
+ clif_displaymessage(fd, output);
+ }
+ if ((equip = pl_sd->status.inventory[i].equip)) {
+ strcpy(equipstr, "| equiped: ");
+ if (equip & 4)
+ strcat(equipstr, "robe/gargment, ");
+ if (equip & 8)
+ strcat(equipstr, "left accessory, ");
+ if (equip & 16)
+ strcat(equipstr, "body/armor, ");
+ if ((equip & 34) == 2)
+ strcat(equipstr, "right hand, ");
+ if ((equip & 34) == 32)
+ strcat(equipstr, "left hand, ");
+ if ((equip & 34) == 34)
+ strcat(equipstr, "both hands, ");
+ if (equip & 64)
+ strcat(equipstr, "feet, ");
+ if (equip & 128)
+ strcat(equipstr, "right accessory, ");
+ if ((equip & 769) == 1)
+ strcat(equipstr, "lower head, ");
+ if ((equip & 769) == 256)
+ strcat(equipstr, "top head, ");
+ if ((equip & 769) == 257)
+ strcat(equipstr, "lower/top head, ");
+ if ((equip & 769) == 512)
+ strcat(equipstr, "mid head, ");
+ if ((equip & 769) == 512)
+ strcat(equipstr, "lower/mid head, ");
+ if ((equip & 769) == 769)
+ strcat(equipstr, "lower/mid/top head, ");
+ // remove final ', '
+ equipstr[strlen(equipstr) - 2] = '\0';
+ } else
+ memset(equipstr, '\0', sizeof(equipstr));
+ if (sd->status.inventory[i].refine)
+ sprintf(output, "%d %s %+d (%s %+d, id: %d) %s", pl_sd->status.inventory[i].amount, item_data->name, pl_sd->status.inventory[i].refine, item_data->jname, pl_sd->status.inventory[i].refine, pl_sd->status.inventory[i].nameid, equipstr);
+ else
+ sprintf(output, "%d %s (%s, id: %d) %s", pl_sd->status.inventory[i].amount, item_data->name, item_data->jname, pl_sd->status.inventory[i].nameid, equipstr);
+ clif_displaymessage(fd, output);
+ memset(output, '\0', sizeof(output));
+ counter2 = 0;
+ for (j = 0; j < item_data->slot; j++) {
+ if (pl_sd->status.inventory[i].card[j]) {
+ if ((item_temp = itemdb_search(pl_sd->status.inventory[i].card[j])) != NULL) {
+ if (output[0] == '\0')
+ sprintf(outputtmp, " -> (card(s): #%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
+ else
+ sprintf(outputtmp, "#%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
+ strcat(output, outputtmp);
+ }
+ }
+ }
+ if (output[0] != '\0') {
+ output[strlen(output) - 2] = ')';
+ output[strlen(output) - 1] = '\0';
+ clif_displaymessage(fd, output);
+ }
+ }
+ }
+ if (count == 0)
+ clif_displaymessage(fd, "No item found on this player.");
+ else {
+ sprintf(output, "%d item(s) found in %d kind(s) of items.", counter, count);
+ clif_displaymessage(fd, output);
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @charstoragelist <character>: Displays the items list of a player's storage.
+ *------------------------------------------
+ */
+int
+atcommand_character_storage_list(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct storage *stor;
+ struct map_session_data *pl_sd;
+ struct item_data *item_data, *item_temp;
+ int i, j, count, counter, counter2;
+ char character[100], output[200], outputtmp[200];
+
+ memset(character, '\0', sizeof(character));
+ memset(output, '\0', sizeof(output));
+ memset(outputtmp, '\0', sizeof(outputtmp));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @charitemlist <char name>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can look items only lower or same level
+ if((stor = account2storage2(pl_sd->status.account_id)) != NULL) {
+ counter = 0;
+ count = 0;
+ for (i = 0; i < MAX_STORAGE; i++) {
+ if (stor->storage[i].nameid > 0 && (item_data = itemdb_search(stor->storage[i].nameid)) != NULL) {
+ counter = counter + stor->storage[i].amount;
+ count++;
+ if (count == 1) {
+ sprintf(output, "------ Storage items list of '%s' ------", pl_sd->status.name);
+ clif_displaymessage(fd, output);
+ }
+ if (stor->storage[i].refine)
+ sprintf(output, "%d %s %+d (%s %+d, id: %d)", stor->storage[i].amount, item_data->name, stor->storage[i].refine, item_data->jname, stor->storage[i].refine, stor->storage[i].nameid);
+ else
+ sprintf(output, "%d %s (%s, id: %d)", stor->storage[i].amount, item_data->name, item_data->jname, stor->storage[i].nameid);
+ clif_displaymessage(fd, output);
+ memset(output, '\0', sizeof(output));
+ counter2 = 0;
+ for (j = 0; j < item_data->slot; j++) {
+ if (stor->storage[i].card[j]) {
+ if ((item_temp = itemdb_search(stor->storage[i].card[j])) != NULL) {
+ if (output[0] == '\0')
+ sprintf(outputtmp, " -> (card(s): #%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
+ else
+ sprintf(outputtmp, "#%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
+ strcat(output, outputtmp);
+ }
+ }
+ }
+ if (output[0] != '\0') {
+ output[strlen(output) - 2] = ')';
+ output[strlen(output) - 1] = '\0';
+ clif_displaymessage(fd, output);
+ }
+ }
+ }
+ if (count == 0)
+ clif_displaymessage(fd, "No item found in the storage of this player.");
+ else {
+ sprintf(output, "%d item(s) found in %d kind(s) of items.", counter, count);
+ clif_displaymessage(fd, output);
+ }
+ } else {
+ clif_displaymessage(fd, "This player has no storage.");
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @charcartlist <character>: Displays the items list of a player's cart.
+ *------------------------------------------
+ */
+int
+atcommand_character_cart_list(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd;
+ struct item_data *item_data, *item_temp;
+ int i, j, count, counter, counter2;
+ char character[100], output[200], outputtmp[200];
+
+ memset(character, '\0', sizeof(character));
+ memset(output, '\0', sizeof(output));
+ memset(outputtmp, '\0', sizeof(outputtmp));
+
+ if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
+ clif_displaymessage(fd, "Please, enter a player name (usage: @charitemlist <char name>).");
+ return -1;
+ }
+
+ if ((pl_sd = map_nick2sd(character)) != NULL) {
+ if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can look items only lower or same level
+ counter = 0;
+ count = 0;
+ for (i = 0; i < MAX_CART; i++) {
+ if (pl_sd->status.cart[i].nameid > 0 && (item_data = itemdb_search(pl_sd->status.cart[i].nameid)) != NULL) {
+ counter = counter + pl_sd->status.cart[i].amount;
+ count++;
+ if (count == 1) {
+ sprintf(output, "------ Cart items list of '%s' ------", pl_sd->status.name);
+ clif_displaymessage(fd, output);
+ }
+ if (pl_sd->status.cart[i].refine)
+ sprintf(output, "%d %s %+d (%s %+d, id: %d)", pl_sd->status.cart[i].amount, item_data->name, pl_sd->status.cart[i].refine, item_data->jname, pl_sd->status.cart[i].refine, pl_sd->status.cart[i].nameid);
+ else
+ sprintf(output, "%d %s (%s, id: %d)", pl_sd->status.cart[i].amount, item_data->name, item_data->jname, pl_sd->status.cart[i].nameid);
+ clif_displaymessage(fd, output);
+ memset(output, '\0', sizeof(output));
+ counter2 = 0;
+ for (j = 0; j < item_data->slot; j++) {
+ if (pl_sd->status.cart[i].card[j]) {
+ if ((item_temp = itemdb_search(pl_sd->status.cart[i].card[j])) != NULL) {
+ if (output[0] == '\0')
+ sprintf(outputtmp, " -> (card(s): #%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
+ else
+ sprintf(outputtmp, "#%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
+ strcat(output, outputtmp);
+ }
+ }
+ }
+ if (output[0] != '\0') {
+ output[strlen(output) - 2] = ')';
+ output[strlen(output) - 1] = '\0';
+ clif_displaymessage(fd, output);
+ }
+ }
+ }
+ if (count == 0)
+ clif_displaymessage(fd, "No item found in the cart of this player.");
+ else {
+ sprintf(output, "%d item(s) found in %d kind(s) of items.", counter, count);
+ clif_displaymessage(fd, output);
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
+ return -1;
+ }
+ } else {
+ clif_displaymessage(fd, msg_table[3]); // Character not found.
+ return -1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @killer by MouseJstr
+ * enable killing players even when not in pvp
+ *------------------------------------------
+ */
+int
+atcommand_killer(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ sd->special_state.killer = !sd->special_state.killer;
+
+ if(sd->special_state.killer)
+ clif_displaymessage(fd, msg_table[241]);
+ else
+ clif_displaymessage(fd, msg_table[242]);
+
+ return 0;
+}
+
+/*==========================================
+ * @killable by MouseJstr
+ * enable other people killing you
+ *------------------------------------------
+ */
+int
+atcommand_killable(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ sd->special_state.killable = !sd->special_state.killable;
+
+ if(sd->special_state.killable)
+ clif_displaymessage(fd, msg_table[242]);
+ else
+ clif_displaymessage(fd, msg_table[241]);
+
+ return 0;
+}
+
+/*==========================================
+ * @charkillable by MouseJstr
+ * enable another player to be killed
+ *------------------------------------------
+ */
+int
+atcommand_charkillable(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd = NULL;
+
+ if (!message || !*message)
+ return -1;
+
+ if((pl_sd=map_nick2sd((char *) message)) == NULL)
+ return -1;
+
+ pl_sd->special_state.killable = !pl_sd->special_state.killable;
+
+ if(pl_sd->special_state.killable)
+ clif_displaymessage(fd, "The player is now killable");
+ else
+ clif_displaymessage(fd, "The player is no longer killable");
+
+ return 0;
+}
+
+
+/*==========================================
+ * @skillon by MouseJstr
+ * turn skills on for the map
+ *------------------------------------------
+ */
+int
+atcommand_skillon(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ map[sd->bl.m].flag.noskill = 0;
+ clif_displaymessage(fd, msg_table[244]);
+ return 0;
+}
+
+/*==========================================
+ * @skilloff by MouseJstr
+ * Turn skills off on the map
+ *------------------------------------------
+ */
+int
+atcommand_skilloff(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ map[sd->bl.m].flag.noskill = 1;
+ clif_displaymessage(fd, msg_table[243]);
+ return 0;
+}
+
+/*==========================================
+ * @npcmove by MouseJstr
+ *
+ * move a npc
+ *------------------------------------------
+ */
+int
+atcommand_npcmove(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char character[100];
+ int x = 0, y = 0;
+ struct npc_data *nd = 0;
+
+ if( sd == NULL )
+ return -1;
+
+ if (!message || !*message)
+ return -1;
+
+ memset(character, '\0', sizeof character);
+
+ if (sscanf(message, "%d %d %99[^\n]", &x, &y, character) < 4)
+ return -1;
+
+ nd=npc_name2id(character);
+ if (nd==NULL)
+ return -1;
+
+ npc_enable(character, 0);
+ nd->bl.x = x;
+ nd->bl.y = y;
+ npc_enable(character, 1);
+
+ return 0;
+}
+
+/*==========================================
+ * @addwarp by MouseJstr
+ *
+ * Create a new static warp point.
+ *------------------------------------------
+ */
+int
+atcommand_addwarp(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char w1[64], w3[64], w4[64];
+ char map[30], output[200];
+ int x,y,ret;
+
+ if (!message || !*message)
+ return -1;
+
+ if (sscanf(message, "%99s %d %d[^\n]", map, &x, &y ) < 3)
+ return -1;
+
+ sprintf(w1,"%s,%d,%d", sd->mapname, sd->bl.x, sd->bl.y);
+ sprintf(w3,"%s%d%d%d%d", map,sd->bl.x, sd->bl.y, x, y);
+ sprintf(w4,"1,1,%s.gat,%d,%d", map, x, y);
+
+ ret = npc_parse_warp(w1, "warp", w3, w4);
+
+ sprintf(output, "New warp NPC => %s",w3);
+
+ clif_displaymessage(fd, output);
+
+ return ret;
+}
+
+/*==========================================
+ * @follow by [MouseJstr]
+ *
+ * Follow a player .. staying no more then 5 spaces away
+ *------------------------------------------
+ */
+int
+atcommand_follow(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd = NULL;
+
+ if (!message || !*message)
+ return -1;
+ if((pl_sd=map_nick2sd((char *) message)) != NULL)
+ pc_follow(sd, pl_sd->bl.id);
+ else
+ return 1;
+ return 0;
+}
+
+
+/*==========================================
+ * @chareffect by [MouseJstr]
+ *
+ * Create a effect localized on another character
+ *------------------------------------------
+ */
+int
+atcommand_chareffect(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd = NULL;
+ char target[255];
+ int type = 0;
+
+ if (!message || !*message || sscanf(message, "%d %s", &type, target) != 2) {
+ clif_displaymessage(fd, "usage: @chareffect <type+> <target>.");
+ return -1;
+ }
+
+ if((pl_sd=map_nick2sd((char *) target)) == NULL)
+ return -1;
+
+ clif_specialeffect(&pl_sd->bl, type, 0);
+ clif_displaymessage(fd, msg_table[229]); // Your effect has changed.
+
+ return 0;
+}
+/*==========================================
+ * @dropall by [MouseJstr]
+ *
+ * Drop all your possession on the ground
+ *------------------------------------------
+ */
+int
+atcommand_dropall(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int i;
+ for (i = 0; i < MAX_INVENTORY; i++) {
+ if (sd->status.inventory[i].amount) {
+ if(sd->status.inventory[i].equip != 0)
+ pc_unequipitem(sd, i, 0);
+ pc_dropitem(sd, i, sd->status.inventory[i].amount);
+ }
+ }
+ return 0;
+}
+/*==========================================
+ * @chardropall by [MouseJstr]
+ *
+ * Throw all the characters possessions on the ground. Normally
+ * done in response to them being disrespectful of a GM
+ *------------------------------------------
+ */
+int
+atcommand_chardropall(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int i;
+ struct map_session_data *pl_sd = NULL;
+
+ if (!message || !*message)
+ return -1;
+ if((pl_sd=map_nick2sd((char *) message)) == NULL)
+ return -1;
+ for (i = 0; i < MAX_INVENTORY; i++) {
+ if (pl_sd->status.inventory[i].amount) {
+ if(pl_sd->status.inventory[i].equip != 0)
+ pc_unequipitem(pl_sd, i, 0);
+ pc_dropitem(pl_sd, i, pl_sd->status.inventory[i].amount);
+ }
+ }
+
+ clif_displaymessage(pl_sd->fd, "Ever play 52 card pickup?");
+ clif_displaymessage(fd, "It is done");
+ //clif_displaymessage(fd, "It is offical.. your a jerk");
+
+ return 0;
+}
+/*==========================================
+ * @storeall by [MouseJstr]
+ *
+ * Put everything into storage to simplify your inventory to make
+ * debugging easie
+ *------------------------------------------
+ */
+int
+atcommand_storeall(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int i;
+ if (storage_storageopen(sd) == 1) {
+ clif_displaymessage(fd, "run this command again..");
+ return 0;
+ }
+ for (i = 0; i < MAX_INVENTORY; i++) {
+ if (sd->status.inventory[i].amount) {
+ if(sd->status.inventory[i].equip != 0)
+ pc_unequipitem(sd, i, 0);
+ storage_storageadd(sd, i, sd->status.inventory[i].amount);
+ }
+ }
+ storage_storageclose(sd);
+
+ clif_displaymessage(fd, "It is done");
+ return 0;
+}
+/*==========================================
+ * @charstoreall by [MouseJstr]
+ *
+ * A way to screw with players who piss you off
+ *------------------------------------------
+ */
+int
+atcommand_charstoreall(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int i;
+ struct map_session_data *pl_sd = NULL;
+
+ if (!message || !*message)
+ return -1;
+ if((pl_sd=map_nick2sd((char *) message)) == NULL)
+ return -1;
+
+ if (storage_storageopen(pl_sd) == 1) {
+ clif_displaymessage(fd, "Had to open the characters storage window...");
+ clif_displaymessage(fd, "run this command again..");
+ return 0;
+ }
+ for (i = 0; i < MAX_INVENTORY; i++) {
+ if (pl_sd->status.inventory[i].amount) {
+ if(pl_sd->status.inventory[i].equip != 0)
+ pc_unequipitem(pl_sd, i, 0);
+ storage_storageadd(pl_sd, i, sd->status.inventory[i].amount);
+ }
+ }
+ storage_storageclose(pl_sd);
+
+ clif_displaymessage(pl_sd->fd, "Everything you own has been put away for safe keeping.");
+ clif_displaymessage(pl_sd->fd, "go to the nearest kafka to retrieve it..");
+ clif_displaymessage(pl_sd->fd, " -- the management");
+
+ clif_displaymessage(fd, "It is done");
+
+ return 0;
+}
+/*==========================================
+ * @skillid by [MouseJstr]
+ *
+ * lookup a skill by name
+ *------------------------------------------
+ */
+int
+atcommand_skillid(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int skillen = 0, idx = 0;
+ if (!message || !*message)
+ return -1;
+ skillen = strlen(message);
+ while (skill_names[idx].id != 0) {
+ if ((strnicmp(skill_names[idx].name, message, skillen) == 0) ||
+ (strnicmp(skill_names[idx].desc, message, skillen) == 0)) {
+ char output[255];
+ sprintf(output, "skill %d: %s", skill_names[idx].id, skill_names[idx].desc);
+ clif_displaymessage(fd, output);
+ }
+ idx++;
+ }
+ return 0;
+}
+/*==========================================
+ * @useskill by [MouseJstr]
+ *
+ * A way of using skills without having to find them in the skills menu
+ *------------------------------------------
+ */
+int
+atcommand_useskill(const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd = NULL;
+ int skillnum;
+ int skilllv;
+ int inf;
+ char target[255];
+
+ if (!message || !*message)
+ return -1;
+ if(sscanf(message, "%d %d %s", &skillnum, &skilllv, target) != 3) {
+ clif_displaymessage(fd, "Usage: @useskill <skillnum> <skillv> <target>");
+ return -1;
+ }
+ if((pl_sd=map_nick2sd(target)) == NULL) {
+ return -1;
+ }
+
+ inf = skill_get_inf(skillnum);
+
+ if ((inf == 2) || (inf == 1))
+ skill_use_pos(sd, pl_sd->bl.x, pl_sd->bl.y, skillnum, skilllv);
+ else
+ skill_use_id(sd, pl_sd->bl.id, skillnum, skilllv);
+
+ return 0;
+}
+/*==========================================
+ * It is made to rain.
+ *------------------------------------------
+ */
+int
+atcommand_rain(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int effno = 0;
+ effno = 161;
+ nullpo_retr(-1, sd);
+ if (effno < 0 || map[sd->bl.m].flag.rain)
+ return -1;
+
+ map[sd->bl.m].flag.rain=1;
+ clif_specialeffect(&sd->bl,effno,2);
+ return 0;
+}
+/*==========================================
+ * It is made to snow.
+ *------------------------------------------
+ */
+int
+atcommand_snow(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int effno = 0;
+ effno = 162;
+ nullpo_retr(-1, sd);
+ if (effno < 0 || map[sd->bl.m].flag.snow)
+ return -1;
+
+ map[sd->bl.m].flag.snow=1;
+ clif_specialeffect(&sd->bl,effno,2);
+ return 0;
+}
+
+/*==========================================
+ * Cherry tree snowstorm is made to fall. (Sakura)
+ *------------------------------------------
+ */
+int
+atcommand_sakura(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int effno = 0;
+ effno = 163;
+ nullpo_retr(-1, sd);
+ if (effno < 0 || map[sd->bl.m].flag.sakura)
+ return -1;
+
+ map[sd->bl.m].flag.sakura=1;
+ clif_specialeffect(&sd->bl,effno,2);
+ return 0;
+}
+
+/*==========================================
+ * Fog hangs over.
+ *------------------------------------------
+ */
+int
+atcommand_fog(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int effno = 0;
+ effno = 233;
+ nullpo_retr(-1, sd);
+ if (effno < 0 || map[sd->bl.m].flag.fog)
+ return -1;
+
+ map[sd->bl.m].flag.fog=1;
+ clif_specialeffect(&sd->bl,effno,2);
+
+ return 0;
+}
+
+/*==========================================
+ * Fallen leaves fall.
+ *------------------------------------------
+ */
+int
+atcommand_leaves(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int effno = 0;
+ effno = 333;
+ nullpo_retr(-1, sd);
+ if (effno < 0 || map[sd->bl.m].flag.leaves)
+ return -1;
+
+ map[sd->bl.m].flag.leaves=1;
+ clif_specialeffect(&sd->bl,effno,2);
+ return 0;
+}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int
+atcommand_summon(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char name[100];
+ int mob_id = 0;
+ int x = 0;
+ int y = 0;
+ int id = 0;
+ struct mob_data *md;
+ unsigned int tick=gettick();
+
+ nullpo_retr(-1, sd);
+
+ if (!message || !*message)
+ return -1;
+ if (sscanf(message, "%99s", name) < 1)
+ return -1;
+
+ if ((mob_id = atoi(name)) == 0)
+ mob_id = mobdb_searchname(name);
+ if(mob_id == 0)
+ return -1;
+
+ x = sd->bl.x + (rand() % 10 - 5);
+ y = sd->bl.y + (rand() % 10 - 5);
+
+ id = mob_once_spawn(sd,"this", x, y, "--ja--", mob_id, 1, "");
+ if((md=(struct mob_data *)map_id2bl(id))){
+ md->master_id=sd->bl.id;
+ md->state.special_mob_ai=1;
+ md->mode=mob_db[md->class].mode|0x04;
+ md->deletetimer=add_timer(tick+60000,mob_timer_delete,id,0);
+ clif_misceffect2(&md->bl,344);
+ }
+ clif_skill_poseffect(&sd->bl,AM_CALLHOMUN,1,x,y,tick);
+
+ return 0;
+}
+
+
+/*==========================================
+ * @adjcmdlvl by [MouseJstr]
+ *
+ * Temp adjust the GM level required to use a GM command
+ *
+ * Used during beta testing to allow players to use GM commands
+ * for short periods of time
+ *------------------------------------------
+ */
+int
+atcommand_adjcmdlvl(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int i, newlev;
+ char cmd[100];
+
+ if (!message || !*message || sscanf(message, "%d %s", &newlev, cmd) != 2) {
+ clif_displaymessage(fd, "usage: @adjcmdlvl <lvl> <command>.");
+ return -1;
+ }
+
+ for (i = 0; atcommand_info[i].type != AtCommand_None; i++)
+ if (strcmpi(cmd, atcommand_info[i].command+1) == 0) {
+ atcommand_info[i].level = newlev;
+ clif_displaymessage(fd, "@command level changed.");
+ return 0;
+ }
+
+ clif_displaymessage(fd, "@command not found.");
+ return -1;
+}
+
+/*==========================================
+ * @adjgmlvl by [MouseJstr]
+ *
+ * Create a temp GM
+ *
+ * Used during beta testing to allow players to use GM commands
+ * for short periods of time
+ *------------------------------------------
+ */
+int
+atcommand_adjgmlvl(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int newlev;
+ char user[100];
+ struct map_session_data *pl_sd;
+
+ if (!message || !*message || sscanf(message, "%d %[^\r\n]", &newlev, user) != 2) {
+ clif_displaymessage(fd, "usage: @adjgmlvl <lvl> <user>.");
+ return -1;
+ }
+
+ if((pl_sd=map_nick2sd((char *) user)) == NULL)
+ return -1;
+
+ pc_set_gm_level(pl_sd->status.account_id, newlev);
+
+ return 0;
+}
+
+
+/*==========================================
+ * @trade by [MouseJstr]
+ *
+ * Open a trade window with a remote player
+ *
+ * If I have to jump to a remote player one more time, I am
+ * gonna scream!
+ *------------------------------------------
+ */
+int
+atcommand_trade(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd = NULL;
+
+ if (!message || !*message)
+ return -1;
+ if((pl_sd=map_nick2sd((char *) message)) != NULL) {
+ trade_traderequest(sd, pl_sd->bl.id);
+ return 0;
+ }
+ return -1;
+}
+
+/*==========================================
+ * @setbattleflag by [MouseJstr]
+ *
+ * set a battle_config flag without having to reboot
+ */
+int
+atcommand_setbattleflag(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char flag[128], value[128];
+
+ if (!message || !*message || sscanf(message, "%s %s", flag, value) != 2) {
+ clif_displaymessage(fd, "usage: @setbattleflag <flag> <value>.");
+ return -1;
+ }
+
+ if (battle_set_value(flag, value) == 0)
+ clif_displaymessage(fd, "unknown battle_config flag");
+ else
+ clif_displaymessage(fd, "battle_config set as requested");
+
+ return 0;
+}
+
+
+/*===========================
+ * @unmute [Valaris]
+ *===========================
+*/
+int atcommand_unmute(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ struct map_session_data *pl_sd = NULL;
+ if (!message || !*message)
+ return -1;
+
+ if((pl_sd=map_nick2sd((char *) message)) != NULL) {
+ if(pl_sd->sc_data[SC_NOCHAT].timer!=-1) {
+ skill_status_change_end(&pl_sd->bl,SC_NOCHAT,-1);
+ clif_displaymessage(sd->fd,"Player unmuted");
+ }
+ else
+ clif_displaymessage(sd->fd,"Player is not muted");
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * @uptime by MC Cameri
+ *------------------------------------------
+ */
+int
+atcommand_uptime(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char output[200];
+ long seconds = 0, day = 24*60*60, hour = 60*60,
+ minute = 60, days = 0, hours = 0, minutes = 0;
+
+ seconds = (gettick()-ticks)/CLOCKS_PER_SEC;
+ days = seconds/day;
+ seconds -= (seconds/day>0)?(seconds/day)*day:0;
+ hours = seconds/hour;
+ seconds -= (seconds/hour>0)?(seconds/hour)*hour:0;
+ minutes = seconds/minute;
+ seconds -= (seconds/minute>0)?(seconds/minute)*minute:0;
+
+ snprintf(output, sizeof(output), msg_table[245], days, hours, minutes, seconds);
+ clif_displaymessage(fd,output);
+ return 0;
+}
+
+#ifndef TXT_ONLY /* Begin SQL-Only commands */
+
+/*==========================================
+ * Mail System commands by [Valaris]
+ *------------------------------------------
+ */
+int atcommand_listmail(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ if(!battle_config.mail_system)
+ return 0;
+
+ nullpo_retr(-1, sd);
+
+ if(strlen(command)==12)
+ mail_check(sd,3);
+ else if(strlen(command)==9)
+ mail_check(sd,2);
+ else
+ mail_check(sd,1);
+ return 0;
+}
+
+int atcommand_readmail(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ if(!battle_config.mail_system)
+ return 0;
+
+ nullpo_retr(-1, sd);
+
+ if (!message || !*message) {
+ clif_displaymessage(sd->fd,"You must specify a message number.");
+ return 0;
+ }
+
+ if(strlen(command)==11)
+ mail_delete(sd,atoi(message));
+ else
+ mail_read(sd,atoi(message));
+
+ return 0;
+}
+
+int atcommand_sendmail(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char name[24],text[80];
+
+ if(!battle_config.mail_system)
+ return 0;
+
+ nullpo_retr(-1, sd);
+
+ if (!message || !*message) {
+ clif_displaymessage(sd->fd,"You must specify a recipient and a message.");
+ return 0;
+ }
+
+ if ((sscanf(message, "\"%[^\"]\" %79[^\n]", name, text) < 2) &&
+ (sscanf(message, "%23s %79[^\n]", name, text) < 2)) {
+ clif_displaymessage(sd->fd,"You must specify a recipient and a message.");
+ return 0;
+ }
+
+ if(strlen(command)==17)
+ mail_send(sd,name,text,1);
+ else
+ mail_send(sd,name,text,0);
+
+ return 0;
+}
+
+/*==========================================
+ * Refresh online command for SQL [Valaris]
+ * Will refresh and check online column of
+ * players and set correctly.
+ *------------------------------------------
+ */
+int atcommand_refreshonline(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ nullpo_retr(-1, sd);
+
+ char_online_check();
+
+ return 0;
+}
+
+#endif /* end sql only */
diff --git a/src/map/atcommand.h b/src/map/atcommand.h
new file mode 100644
index 000000000..72d57af6a
--- /dev/null
+++ b/src/map/atcommand.h
@@ -0,0 +1,243 @@
+// $Id: atcommand.h 148 2004-09-30 14:05:37Z MouseJstr $
+#ifndef _ATCOMMAND_H_
+#define _ATCOMMAND_H_
+
+enum AtCommandType {
+ AtCommand_None = -1,
+ AtCommand_Broadcast = 0,
+ AtCommand_LocalBroadcast,
+ AtCommand_MapMove,
+ AtCommand_ResetState,
+ AtCommand_RuraP,
+ AtCommand_Rura,
+ AtCommand_Warp,
+ AtCommand_Where,
+ AtCommand_JumpTo,
+ AtCommand_Jump,
+ AtCommand_Who,
+ AtCommand_Who2,
+ AtCommand_Who3,
+ AtCommand_WhoMap,
+ AtCommand_WhoMap2,
+ AtCommand_WhoMap3,
+ AtCommand_WhoGM,
+ AtCommand_Save,
+ AtCommand_Load,
+ AtCommand_Speed,
+ AtCommand_Storage,
+ AtCommand_GuildStorage,
+ AtCommand_Option,
+ AtCommand_Hide,
+ AtCommand_JobChange,
+ AtCommand_JobChange2,
+ AtCommand_JobChange3,
+ AtCommand_Die,
+ AtCommand_Kill,
+ AtCommand_Alive,
+ AtCommand_Kami,
+ AtCommand_KamiB,
+ AtCommand_Heal,
+ AtCommand_Item,
+ AtCommand_Item2,
+ AtCommand_ItemReset,
+ AtCommand_ItemCheck,
+ AtCommand_BaseLevelUp,
+ AtCommand_JobLevelUp,
+ AtCommand_H,
+ AtCommand_Help,
+ AtCommand_GM,
+ AtCommand_PvPOff,
+ AtCommand_PvPOn,
+ AtCommand_GvGOff,
+ AtCommand_GvGOn,
+ AtCommand_Model,
+ AtCommand_Go,
+ AtCommand_Spawn,
+ AtCommand_Monster,
+ AtCommand_KillMonster,
+ AtCommand_KillMonster2,
+ AtCommand_Refine,
+ AtCommand_Produce,
+ AtCommand_Memo,
+ AtCommand_GAT,
+ AtCommand_Packet,
+ AtCommand_StatusPoint,
+ AtCommand_SkillPoint,
+ AtCommand_Zeny,
+ AtCommand_Param,
+ AtCommand_Strength,
+ AtCommand_Agility,
+ AtCommand_Vitality,
+ AtCommand_Intelligence,
+ AtCommand_Dexterity,
+ AtCommand_Luck,
+ AtCommand_GuildLevelUp,
+ AtCommand_MakeEgg,
+ AtCommand_PetFriendly,
+ AtCommand_PetHungry,
+ AtCommand_PetRename,
+ AtCommand_CharPetRename, // by Yor
+ AtCommand_Recall,
+ AtCommand_CharacterJob,
+ AtCommand_CharacterJob2,
+ AtCommand_CharacterJob3,
+ AtCommand_Revive,
+ AtCommand_CharacterStats,
+ AtCommand_CharacterStatsAll,
+ AtCommand_CharacterOption,
+ AtCommand_CharacterSave,
+ AtCommand_CharacterLoad,
+ AtCommand_Night,
+ AtCommand_Day,
+ AtCommand_Doom,
+ AtCommand_DoomMap,
+ AtCommand_Raise,
+ AtCommand_RaiseMap,
+ AtCommand_CharacterBaseLevel,
+ AtCommand_CharacterJobLevel,
+ AtCommand_Kick,
+ AtCommand_KickAll,
+ AtCommand_AllSkill,
+ AtCommand_QuestSkill,
+ AtCommand_CharQuestSkill,
+ AtCommand_LostSkill,
+ AtCommand_CharLostSkill,
+ AtCommand_SpiritBall,
+ AtCommand_Party,
+ AtCommand_Guild,
+ AtCommand_AgitStart,
+ AtCommand_AgitEnd,
+ AtCommand_MapExit,
+ AtCommand_IDSearch,
+ AtCommand_CharSkReset,
+ AtCommand_CharStReset,
+ AtCommand_CharReset,
+ //by chbrules
+ AtCommand_CharModel,
+ AtCommand_CharSKPoint,
+ AtCommand_CharSTPoint,
+ AtCommand_CharZeny,
+ AtCommand_RecallAll,
+ AtCommand_ReloadItemDB,
+ AtCommand_ReloadMobDB,
+ AtCommand_ReloadSkillDB,
+#ifndef TXT_ONLY
+ AtCommand_Rehash,
+#else /* TXT_ONLY */
+ AtCommand_ReloadScript,
+#endif /* TXT_ONLY */
+ AtCommand_ReloadGMDB,
+ AtCommand_MapInfo,
+ AtCommand_Dye,
+ AtCommand_Hstyle,
+ AtCommand_Hcolor,
+ AtCommand_StatAll,
+ AtCommand_CharChangeSex, // by Yor
+ AtCommand_CharBlock, // by Yor
+ AtCommand_CharBan, // by Yor
+ AtCommand_CharUnBlock, // by Yor
+ AtCommand_CharUnBan, // by Yor
+ AtCommand_MountPeco, // by Valaris
+ AtCommand_CharMountPeco, // by Yor
+ AtCommand_GuildSpy, // [Syrus22]
+ AtCommand_PartySpy, // [Syrus22]
+ AtCommand_RepairAll, // [Valaris]
+ AtCommand_GuildRecall, // by Yor
+ AtCommand_PartyRecall, // by Yor
+// AtCommand_Nuke, // [Valaris]
+ AtCommand_Enablenpc,
+ AtCommand_Disablenpc,
+ AtCommand_ServerTime, // by Yor
+ AtCommand_CharDelItem, // by Yor
+ AtCommand_Jail, // by Yor
+ AtCommand_UnJail, // by Yor
+ AtCommand_Disguise, // [Valaris]
+ AtCommand_UnDisguise, // by Yor
+ AtCommand_CharDisguise, // Kalaspuff
+ AtCommand_CharUnDisguise, // Kalaspuff
+ AtCommand_EMail, // by Yor
+ AtCommand_Hatch,
+ AtCommand_Effect, // by Apple
+ AtCommand_Char_Item_List, // by Yor
+ AtCommand_Char_Storage_List, // by Yor
+ AtCommand_Char_Cart_List, // by Yor
+ AtCommand_AddWarp, // by MouseJstr
+ AtCommand_Follow, // by MouseJstr
+ AtCommand_SkillOn, // by MouseJstr
+ AtCommand_SkillOff, // by MouseJstr
+ AtCommand_Killer, // by MouseJstr
+ AtCommand_NpcMove, // by MouseJstr
+ AtCommand_Killable, // by MouseJstr
+ AtCommand_CharKillable, // by MouseJstr
+ AtCommand_Chareffect, // by MouseJstr
+ AtCommand_Chardye, // by MouseJstr
+ AtCommand_Charhairstyle, // by MouseJstr
+ AtCommand_Charhaircolor, // by MouseJstr
+ AtCommand_Dropall, // by MouseJstr
+ AtCommand_Chardropall, // by MouseJstr
+ AtCommand_Storeall, // by MouseJstr
+ AtCommand_Charstoreall, // by MouseJstr
+ AtCommand_Skillid, // by MouseJstr
+ AtCommand_Useskill, // by MouseJstr
+ AtCommand_Summon,
+ AtCommand_Rain,
+ AtCommand_Snow,
+ AtCommand_Sakura,
+ AtCommand_Fog,
+ AtCommand_Leaves,
+ AtCommand_AdjGmLvl, // MouseJstr
+ AtCommand_AdjCmdLvl, // MouseJstr
+ AtCommand_Trade, // MouseJstr
+ AtCommand_Send,
+ AtCommand_SetBattleFlag,
+ AtCommand_UnMute,
+ AtCommand_UpTime,
+ // SQL-only commands start
+#ifndef TXT_ONLY
+ AtCommand_CheckMail, // [Valaris]
+ AtCommand_ListMail, // [Valaris]
+ AtCommand_ListNewMail, // [Valaris]
+ AtCommand_ReadMail, // [Valaris]
+ AtCommand_SendMail, // [Valaris]
+ AtCommand_DeleteMail, // [Valaris]
+ AtCommand_SendPriorityMail, // [Valaris]
+ AtCommand_Sound, // [Valaris]
+ AtCommand_RefreshOnline, // [Valaris]
+ // SQL-only commands end
+#endif
+
+ // end
+ AtCommand_Unknown,
+ AtCommand_MAX
+};
+
+typedef enum AtCommandType AtCommandType;
+
+typedef struct AtCommandInfo {
+ AtCommandType type;
+ const char* command;
+ int level;
+ int (*proc)(const int, struct map_session_data*,
+ const char* command, const char* message);
+} AtCommandInfo;
+
+AtCommandType
+is_atcommand(const int fd, struct map_session_data* sd, const char* message, int gmlvl);
+
+AtCommandType atcommand(
+ const int level, const char* message, AtCommandInfo* info);
+int get_atcommand_level(const AtCommandType type);
+
+char * msg_txt(int msg_number); // [Yor]
+
+int atcommand_item(const int fd, struct map_session_data* sd,const char* command, const char* message); // [Valaris]
+int atcommand_rura(const int fd, struct map_session_data* sd,const char* command, const char* message); // [Yor]
+int atcommand_spawn(const int fd, struct map_session_data* sd, const char* command, const char* message); // [Valaris]
+int atcommand_jumpto(const int fd, struct map_session_data* sd, const char* command, const char* message); // [Yor]
+int atcommand_recall(const int fd, struct map_session_data* sd, const char* command, const char* message); // [Yor]
+
+int atcommand_config_read(const char *cfgName);
+int msg_config_read(const char *cfgName);
+
+#endif
+
diff --git a/src/map/battle.c b/src/map/battle.c
new file mode 100644
index 000000000..b5f7009d8
--- /dev/null
+++ b/src/map/battle.c
@@ -0,0 +1,5387 @@
+// $Id: battle.c,v 1.10 2004/09/29 21:08:17 Akitasha Exp $
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "battle.h"
+
+#include "timer.h"
+#include "nullpo.h"
+#include "malloc.h"
+
+#include "map.h"
+#include "pc.h"
+#include "skill.h"
+#include "mob.h"
+#include "itemdb.h"
+#include "clif.h"
+#include "pet.h"
+#include "guild.h"
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+int attr_fix_table[4][10][10];
+
+struct Battle_Config battle_config;
+
+/*==========================================
+ * 二点間の距離を返す
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+static int distance(int x0,int y0,int x1,int y1)
+{
+ int dx,dy;
+
+ dx=abs(x0-x1);
+ dy=abs(y0-y1);
+ return dx>dy ? dx : dy;
+}
+
+/*==========================================
+ * 自分をロックしている対象の数を返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_counttargeted(struct block_list *bl,struct block_list *src,int target_lv)
+{
+ nullpo_retr(0, bl);
+ if(bl->type == BL_PC)
+ return pc_counttargeted((struct map_session_data *)bl,src,target_lv);
+ else if(bl->type == BL_MOB)
+ return mob_counttargeted((struct mob_data *)bl,src,target_lv);
+ return 0;
+}
+/*==========================================
+ * 対象のClassを返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_class(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ return ((struct mob_data *)bl)->class;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return ((struct map_session_data *)bl)->status.class;
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ return ((struct pet_data *)bl)->class;
+ else
+ return 0;
+}
+/*==========================================
+ * 対象の方向を返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_dir(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ return ((struct mob_data *)bl)->dir;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return ((struct map_session_data *)bl)->dir;
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ return ((struct pet_data *)bl)->dir;
+ else
+ return 0;
+}
+/*==========================================
+ * 対象のレベルを返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_lv(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ return mob_db[((struct mob_data *)bl)->class].lv;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return ((struct map_session_data *)bl)->status.base_level;
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ return ((struct pet_data *)bl)->msd->pet.level;
+ else
+ return 0;
+}
+/*==========================================
+ * 対象の射程を返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_range(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ return mob_db[((struct mob_data *)bl)->class].range;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return ((struct map_session_data *)bl)->attackrange;
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ return mob_db[((struct pet_data *)bl)->class].range;
+ else
+ return 0;
+}
+/*==========================================
+ * 対象のHPを返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_hp(struct block_list *bl)
+{
+ nullpo_retr(1, bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ return ((struct mob_data *)bl)->hp;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return ((struct map_session_data *)bl)->status.hp;
+ else
+ return 1;
+}
+/*==========================================
+ * 対象のMHPを返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_max_hp(struct block_list *bl)
+{
+ nullpo_retr(1, bl);
+ if(bl->type==BL_PC && ((struct map_session_data *)bl))
+ return ((struct map_session_data *)bl)->status.max_hp;
+ else {
+ struct status_change *sc_data=battle_get_sc_data(bl);
+ int max_hp=1;
+ if(bl->type==BL_MOB && ((struct mob_data*)bl)) {
+ max_hp = mob_db[((struct mob_data*)bl)->class].max_hp;
+ if(mob_db[((struct mob_data*)bl)->class].mexp > 0) {
+ if(battle_config.mvp_hp_rate != 100)
+ max_hp = (max_hp * battle_config.mvp_hp_rate)/100;
+ }
+ else {
+ if(battle_config.monster_hp_rate != 100)
+ max_hp = (max_hp * battle_config.monster_hp_rate)/100;
+ }
+ }
+ else if(bl->type==BL_PET && ((struct pet_data*)bl)) {
+ max_hp = mob_db[((struct pet_data*)bl)->class].max_hp;
+ if(mob_db[((struct pet_data*)bl)->class].mexp > 0) {
+ if(battle_config.mvp_hp_rate != 100)
+ max_hp = (max_hp * battle_config.mvp_hp_rate)/100;
+ }
+ else {
+ if(battle_config.monster_hp_rate != 100)
+ max_hp = (max_hp * battle_config.monster_hp_rate)/100;
+ }
+ }
+ if(sc_data) {
+ if(sc_data[SC_APPLEIDUN].timer!=-1)
+ max_hp += ((5+sc_data[SC_APPLEIDUN].val1*2+((sc_data[SC_APPLEIDUN].val2+1)>>1)
+ +sc_data[SC_APPLEIDUN].val3/10) * max_hp)/100;
+ }
+ if(max_hp < 1) max_hp = 1;
+ return max_hp;
+ }
+ return 1;
+}
+/*==========================================
+ * 対象のStrを返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_str(struct block_list *bl)
+{
+ int str=0;
+ struct status_change *sc_data;
+
+ nullpo_retr(0, bl);
+ sc_data=battle_get_sc_data(bl);
+ if(bl->type==BL_MOB && ((struct mob_data *)bl))
+ str = mob_db[((struct mob_data *)bl)->class].str;
+ else if(bl->type==BL_PC && ((struct map_session_data *)bl))
+ return ((struct map_session_data *)bl)->paramc[0];
+ else if(bl->type==BL_PET && ((struct pet_data *)bl))
+ str = mob_db[((struct pet_data *)bl)->class].str;
+
+ if(sc_data) {
+ if(sc_data[SC_LOUD].timer!=-1 && sc_data[SC_QUAGMIRE].timer == -1 && bl->type != BL_PC)
+ str += 4;
+ if( sc_data[SC_BLESSING].timer != -1 && bl->type != BL_PC){ // ブレッシング
+ int race=battle_get_race(bl);
+ if(battle_check_undead(race,battle_get_elem_type(bl)) || race==6 ) str >>= 1; // 悪 魔/不死
+ else str += sc_data[SC_BLESSING].val1; // その他
+ }
+ if(sc_data[SC_TRUESIGHT].timer!=-1 && bl->type != BL_PC) // トゥルーサイト
+ str += 5;
+ }
+ if(str < 0) str = 0;
+ return str;
+}
+/*==========================================
+ * 対象のAgiを返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+
+int battle_get_agi(struct block_list *bl)
+{
+ int agi=0;
+ struct status_change *sc_data;
+
+ nullpo_retr(0, bl);
+ sc_data=battle_get_sc_data(bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ agi=mob_db[((struct mob_data *)bl)->class].agi;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ agi=((struct map_session_data *)bl)->paramc[1];
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ agi=mob_db[((struct pet_data *)bl)->class].agi;
+
+ if(sc_data) {
+ if( sc_data[SC_INCREASEAGI].timer!=-1 && sc_data[SC_QUAGMIRE].timer == -1 && sc_data[SC_DONTFORGETME].timer == -1 &&
+ bl->type != BL_PC) // 速度増加(PCはpc.cで)
+ agi += 2+sc_data[SC_INCREASEAGI].val1;
+
+ if(sc_data[SC_CONCENTRATE].timer!=-1 && sc_data[SC_QUAGMIRE].timer == -1 && bl->type != BL_PC)
+ agi += agi*(2+sc_data[SC_CONCENTRATE].val1)/100;
+
+ if(sc_data[SC_DECREASEAGI].timer!=-1) // 速度減少
+ agi -= 2+sc_data[SC_DECREASEAGI].val1;
+
+ if(sc_data[SC_QUAGMIRE].timer!=-1 ) // クァグマイア
+ agi >>= 1;
+ if(sc_data[SC_TRUESIGHT].timer!=-1 && bl->type != BL_PC) // トゥルーサイト
+ agi += 5;
+ }
+ if(agi < 0) agi = 0;
+ return agi;
+}
+/*==========================================
+ * 対象のVitを返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_vit(struct block_list *bl)
+{
+ int vit=0;
+ struct status_change *sc_data;
+
+ nullpo_retr(0, bl);
+ sc_data=battle_get_sc_data(bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ vit=mob_db[((struct mob_data *)bl)->class].vit;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ vit=((struct map_session_data *)bl)->paramc[2];
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ vit=mob_db[((struct pet_data *)bl)->class].vit;
+ if(sc_data) {
+ if(sc_data[SC_STRIPARMOR].timer != -1 && bl->type!=BL_PC)
+ vit = vit*60/100;
+ if(sc_data[SC_TRUESIGHT].timer!=-1 && bl->type != BL_PC) // トゥルーサイト
+ vit += 5;
+ }
+
+ if(vit < 0) vit = 0;
+ return vit;
+}
+/*==========================================
+ * 対象のIntを返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_int(struct block_list *bl)
+{
+ int int_=0;
+ struct status_change *sc_data;
+
+ nullpo_retr(0, bl);
+ sc_data=battle_get_sc_data(bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ int_=mob_db[((struct mob_data *)bl)->class].int_;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ int_=((struct map_session_data *)bl)->paramc[3];
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ int_=mob_db[((struct pet_data *)bl)->class].int_;
+
+ if(sc_data) {
+ if( sc_data[SC_BLESSING].timer != -1 && bl->type != BL_PC){ // ブレッシング
+ int race=battle_get_race(bl);
+ if(battle_check_undead(race,battle_get_elem_type(bl)) || race==6 ) int_ >>= 1; // 悪 魔/不死
+ else int_ += sc_data[SC_BLESSING].val1; // その他
+ }
+ if( sc_data[SC_STRIPHELM].timer != -1 && bl->type != BL_PC)
+ int_ = int_*60/100;
+ if(sc_data[SC_TRUESIGHT].timer!=-1 && bl->type != BL_PC) // トゥルーサイト
+ int_ += 5;
+ }
+ if(int_ < 0) int_ = 0;
+ return int_;
+}
+/*==========================================
+ * 対象のDexを返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_dex(struct block_list *bl)
+{
+ int dex=0;
+ struct status_change *sc_data;
+
+ nullpo_retr(0, bl);
+ sc_data=battle_get_sc_data(bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ dex=mob_db[((struct mob_data *)bl)->class].dex;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ dex=((struct map_session_data *)bl)->paramc[4];
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ dex=mob_db[((struct pet_data *)bl)->class].dex;
+
+ if(sc_data) {
+ if(sc_data[SC_CONCENTRATE].timer!=-1 && sc_data[SC_QUAGMIRE].timer == -1 && bl->type != BL_PC)
+ dex += dex*(2+sc_data[SC_CONCENTRATE].val1)/100;
+
+ if( sc_data[SC_BLESSING].timer != -1 && bl->type != BL_PC){ // ブレッシング
+ int race=battle_get_race(bl);
+ if(battle_check_undead(race,battle_get_elem_type(bl)) || race==6 ) dex >>= 1; // 悪 魔/不死
+ else dex += sc_data[SC_BLESSING].val1; // その他
+ }
+
+ if(sc_data[SC_QUAGMIRE].timer!=-1 ) // クァグマイア
+ dex >>= 1;
+ if(sc_data[SC_TRUESIGHT].timer!=-1 && bl->type != BL_PC) // トゥルーサイト
+ dex += 5;
+ }
+ if(dex < 0) dex = 0;
+ return dex;
+}
+/*==========================================
+ * 対象のLukを返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_luk(struct block_list *bl)
+{
+ int luk=0;
+ struct status_change *sc_data;
+
+ nullpo_retr(0, bl);
+ sc_data=battle_get_sc_data(bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ luk=mob_db[((struct mob_data *)bl)->class].luk;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ luk=((struct map_session_data *)bl)->paramc[5];
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ luk=mob_db[((struct pet_data *)bl)->class].luk;
+
+ if(sc_data) {
+ if(sc_data[SC_GLORIA].timer!=-1 && bl->type != BL_PC) // グロリア(PCはpc.cで)
+ luk += 30;
+ if(sc_data[SC_CURSE].timer!=-1 ) // 呪い
+ luk=0;
+ if(sc_data[SC_TRUESIGHT].timer!=-1 && bl->type != BL_PC) // トゥルーサイト
+ luk += 5;
+ }
+ if(luk < 0) luk = 0;
+ return luk;
+}
+
+/*==========================================
+ * 対象のFleeを返す(汎用)
+ * 戻りは整数で1以上
+ *------------------------------------------
+ */
+int battle_get_flee(struct block_list *bl)
+{
+ int flee=1;
+ struct status_change *sc_data;
+
+ nullpo_retr(1, bl);
+ sc_data=battle_get_sc_data(bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl)
+ flee=((struct map_session_data *)bl)->flee;
+ else
+ flee=battle_get_agi(bl) + battle_get_lv(bl);
+
+ if(sc_data) {
+ if(sc_data[SC_WHISTLE].timer!=-1 && bl->type != BL_PC)
+ flee += flee*(sc_data[SC_WHISTLE].val1+sc_data[SC_WHISTLE].val2
+ +(sc_data[SC_WHISTLE].val3>>16))/100;
+ if(sc_data[SC_BLIND].timer!=-1 && bl->type != BL_PC)
+ flee -= flee*25/100;
+ if(sc_data[SC_WINDWALK].timer!=-1 && bl->type != BL_PC) // ウィンドウォーク
+ flee += flee*(sc_data[SC_WINDWALK].val2)/100;
+ if(sc_data[SC_SPIDERWEB].timer!=-1 && bl->type != BL_PC) //スパイダーウェブ
+ flee -= flee*50/100;
+ }
+ if(flee < 1) flee = 1;
+ return flee;
+}
+/*==========================================
+ * 対象のHitを返す(汎用)
+ * 戻りは整数で1以上
+ *------------------------------------------
+ */
+int battle_get_hit(struct block_list *bl)
+{
+ int hit=1;
+ struct status_change *sc_data;
+
+ nullpo_retr(1, bl);
+ sc_data=battle_get_sc_data(bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl)
+ hit=((struct map_session_data *)bl)->hit;
+ else
+ hit=battle_get_dex(bl) + battle_get_lv(bl);
+
+ if(sc_data) {
+ if(sc_data[SC_HUMMING].timer!=-1 && bl->type != BL_PC) //
+ hit += hit*(sc_data[SC_HUMMING].val1*2+sc_data[SC_HUMMING].val2
+ +sc_data[SC_HUMMING].val3)/100;
+ if(sc_data[SC_BLIND].timer!=-1 && bl->type != BL_PC) // 呪い
+ hit -= hit*25/100;
+ if(sc_data[SC_TRUESIGHT].timer!=-1 && bl->type != BL_PC) // トゥルーサイト
+ hit += 3*(sc_data[SC_TRUESIGHT].val1);
+ if(sc_data[SC_CONCENTRATION].timer!=-1 && bl->type != BL_PC) //コンセントレーション
+ hit += (hit*(10*(sc_data[SC_CONCENTRATION].val1)))/100;
+ }
+ if(hit < 1) hit = 1;
+ return hit;
+}
+/*==========================================
+ * 対象の完全回避を返す(汎用)
+ * 戻りは整数で1以上
+ *------------------------------------------
+ */
+int battle_get_flee2(struct block_list *bl)
+{
+ int flee2=1;
+ struct status_change *sc_data;
+
+ nullpo_retr(1, bl);
+ sc_data=battle_get_sc_data(bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl){
+ flee2 = battle_get_luk(bl) + 10;
+ flee2 += ((struct map_session_data *)bl)->flee2 - (((struct map_session_data *)bl)->paramc[5] + 10);
+ }
+ else
+ flee2=battle_get_luk(bl)+1;
+
+ if(sc_data) {
+ if(sc_data[SC_WHISTLE].timer!=-1 && bl->type != BL_PC)
+ flee2 += (sc_data[SC_WHISTLE].val1+sc_data[SC_WHISTLE].val2
+ +(sc_data[SC_WHISTLE].val3&0xffff))*10;
+ }
+ if(flee2 < 1) flee2 = 1;
+ return flee2;
+}
+/*==========================================
+ * 対象のクリティカルを返す(汎用)
+ * 戻りは整数で1以上
+ *------------------------------------------
+ */
+int battle_get_critical(struct block_list *bl)
+{
+ int critical=1;
+ struct status_change *sc_data;
+
+ nullpo_retr(1, bl);
+ sc_data=battle_get_sc_data(bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl){
+ critical = battle_get_luk(bl)*3 + 10;
+ critical += ((struct map_session_data *)bl)->critical - ((((struct map_session_data *)bl)->paramc[5]*3) + 10);
+ }
+ else
+ critical=battle_get_luk(bl)*3 + 1;
+
+ if(sc_data) {
+ if(sc_data[SC_FORTUNE].timer!=-1 && bl->type != BL_PC)
+ critical += (10+sc_data[SC_FORTUNE].val1+sc_data[SC_FORTUNE].val2
+ +sc_data[SC_FORTUNE].val3)*10;
+ if(sc_data[SC_EXPLOSIONSPIRITS].timer!=-1 && bl->type != BL_PC)
+ critical += sc_data[SC_EXPLOSIONSPIRITS].val2;
+ if(sc_data[SC_TRUESIGHT].timer!=-1 && bl->type != BL_PC) //トゥルーサイト
+ critical += critical*sc_data[SC_TRUESIGHT].val1/100;
+ }
+ if(critical < 1) critical = 1;
+ return critical;
+}
+/*==========================================
+ * base_atkの取得
+ * 戻りは整数で1以上
+ *------------------------------------------
+ */
+int battle_get_baseatk(struct block_list *bl)
+{
+ struct status_change *sc_data;
+ int batk=1;
+
+ nullpo_retr(1, bl);
+ sc_data=battle_get_sc_data(bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl)
+ batk = ((struct map_session_data *)bl)->base_atk; //設定されているbase_atk
+ else { //それ以外なら
+ int str,dstr;
+ str = battle_get_str(bl); //STR
+ dstr = str/10;
+ batk = dstr*dstr + str; //base_atkを計算する
+ }
+ if(sc_data) { //状態異常あり
+ if(sc_data[SC_PROVOKE].timer!=-1 && bl->type != BL_PC) //PCでプロボック(SM_PROVOKE)状態
+ batk = batk*(100+2*sc_data[SC_PROVOKE].val1)/100; //base_atk増加
+ if(sc_data[SC_CURSE].timer!=-1 ) //呪われていたら
+ batk -= batk*25/100; //base_atkが25%減少
+ if(sc_data[SC_CONCENTRATION].timer!=-1 && bl->type != BL_PC) //コンセントレーション
+ batk += batk*(5*sc_data[SC_CONCENTRATION].val1)/100;
+ }
+ if(batk < 1) batk = 1; //base_atkは最低でも1
+ return batk;
+}
+/*==========================================
+ * 対象のAtkを返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_atk(struct block_list *bl)
+{
+ struct status_change *sc_data;
+ int atk=0;
+
+ nullpo_retr(0, bl);
+ sc_data=battle_get_sc_data(bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl)
+ atk = ((struct map_session_data*)bl)->watk;
+ else if(bl->type==BL_MOB && (struct mob_data *)bl)
+ atk = mob_db[((struct mob_data*)bl)->class].atk1;
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ atk = mob_db[((struct pet_data*)bl)->class].atk1;
+
+ if(sc_data) {
+ if(sc_data[SC_PROVOKE].timer!=-1 && bl->type != BL_PC)
+ atk = atk*(100+2*sc_data[SC_PROVOKE].val1)/100;
+ if(sc_data[SC_CURSE].timer!=-1 )
+ atk -= atk*25/100;
+ if(sc_data[SC_CONCENTRATION].timer!=-1 && bl->type != BL_PC) //コンセントレーション
+ atk += atk*(5*sc_data[SC_CONCENTRATION].val1)/100;
+ }
+ if(atk < 0) atk = 0;
+ return atk;
+}
+/*==========================================
+ * 対象の左手Atkを返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_atk_(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl){
+ int atk=((struct map_session_data*)bl)->watk_;
+
+ if(((struct map_session_data *)bl)->sc_data[SC_CURSE].timer!=-1 )
+ atk -= atk*25/100;
+ return atk;
+ }
+ else
+ return 0;
+}
+/*==========================================
+ * 対象のAtk2を返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_atk2(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return ((struct map_session_data*)bl)->watk2;
+ else {
+ struct status_change *sc_data=battle_get_sc_data(bl);
+ int atk2=0;
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ atk2 = mob_db[((struct mob_data*)bl)->class].atk2;
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ atk2 = mob_db[((struct pet_data*)bl)->class].atk2;
+ if(sc_data) {
+ if( sc_data[SC_IMPOSITIO].timer!=-1)
+ atk2 += sc_data[SC_IMPOSITIO].val1*5;
+ if( sc_data[SC_PROVOKE].timer!=-1 )
+ atk2 = atk2*(100+2*sc_data[SC_PROVOKE].val1)/100;
+ if( sc_data[SC_CURSE].timer!=-1 )
+ atk2 -= atk2*25/100;
+ if(sc_data[SC_DRUMBATTLE].timer!=-1)
+ atk2 += sc_data[SC_DRUMBATTLE].val2;
+ if(sc_data[SC_NIBELUNGEN].timer!=-1 && (battle_get_element(bl)/10) >= 8 )
+ atk2 += sc_data[SC_NIBELUNGEN].val2;
+ if(sc_data[SC_STRIPWEAPON].timer!=-1)
+ atk2 = atk2*90/100;
+ if(sc_data[SC_CONCENTRATION].timer!=-1) //コンセントレーション
+ atk2 += atk2*(5*sc_data[SC_CONCENTRATION].val1)/100;
+ }
+ if(atk2 < 0) atk2 = 0;
+ return atk2;
+ }
+ return 0;
+}
+/*==========================================
+ * 対象の左手Atk2を返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_atk_2(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return ((struct map_session_data*)bl)->watk_2;
+ else
+ return 0;
+}
+/*==========================================
+ * 対象のMAtk1を返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_matk1(struct block_list *bl)
+{
+ struct status_change *sc_data;
+ nullpo_retr(0, bl);
+ sc_data=battle_get_sc_data(bl);
+ if(bl->type==BL_MOB){
+ int matk,int_=battle_get_int(bl);
+ matk = int_+(int_/5)*(int_/5);
+
+ if(sc_data)
+ if(sc_data[SC_MINDBREAKER].timer!=-1 && bl->type != BL_PC)
+ matk = matk*(100+2*sc_data[SC_MINDBREAKER].val1)/100;
+ return matk;
+ }
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return ((struct map_session_data *)bl)->matk1;
+ else if(bl->type==BL_PET){
+ int matk,int_=battle_get_int(bl);
+ matk = int_+(int_/5)*(int_/5);
+
+ if(sc_data)
+ if(sc_data[SC_MINDBREAKER].timer!=-1 && bl->type != BL_PC)
+ matk = matk*(100+2*sc_data[SC_MINDBREAKER].val1)/100;
+ return matk;
+ }
+ else
+ return 0;
+}
+/*==========================================
+ * 対象のMAtk2を返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_matk2(struct block_list *bl)
+{
+ struct status_change *sc_data=battle_get_sc_data(bl);
+ nullpo_retr(0, bl);
+ if(bl->type==BL_MOB){
+ int matk,int_=battle_get_int(bl);
+ matk = int_+(int_/7)*(int_/7);
+
+ if(sc_data)
+ if(sc_data[SC_MINDBREAKER].timer!=-1 && bl->type != BL_PC)
+ matk = matk*(100+2*sc_data[SC_MINDBREAKER].val1)/100;
+ return matk;
+ }
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return ((struct map_session_data *)bl)->matk2;
+ else if(bl->type==BL_PET){
+ int matk,int_=battle_get_int(bl);
+ matk = int_+(int_/7)*(int_/7);
+ if(sc_data)
+ if(sc_data[SC_MINDBREAKER].timer!=-1 && bl->type != BL_PC)
+ matk = matk*(100+2*sc_data[SC_MINDBREAKER].val1)/100;
+ return matk;
+ }
+ else
+ return 0;
+}
+/*==========================================
+ * 対象のDefを返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_def(struct block_list *bl)
+{
+ struct status_change *sc_data;
+ int def=0,skilltimer=-1,skillid=0;
+
+ nullpo_retr(0, bl);
+ sc_data=battle_get_sc_data(bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl){
+ def = ((struct map_session_data *)bl)->def;
+ skilltimer = ((struct map_session_data *)bl)->skilltimer;
+ skillid = ((struct map_session_data *)bl)->skillid;
+ }
+ else if(bl->type==BL_MOB && (struct mob_data *)bl) {
+ def = mob_db[((struct mob_data *)bl)->class].def;
+ skilltimer = ((struct mob_data *)bl)->skilltimer;
+ skillid = ((struct mob_data *)bl)->skillid;
+ }
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ def = mob_db[((struct pet_data *)bl)->class].def;
+
+ if(def < 1000000) {
+ if(sc_data) {
+ //キーピング時はDEF100
+ if( sc_data[SC_KEEPING].timer!=-1)
+ def = 100;
+ //プロボック時は減算
+ if( sc_data[SC_PROVOKE].timer!=-1 && bl->type != BL_PC)
+ def = (def*(100 - 6*sc_data[SC_PROVOKE].val1)+50)/100;
+ //戦太鼓の響き時は加算
+ if( sc_data[SC_DRUMBATTLE].timer!=-1 && bl->type != BL_PC)
+ def += sc_data[SC_DRUMBATTLE].val3;
+ //毒にかかっている時は減算
+ if(sc_data[SC_POISON].timer!=-1 && bl->type != BL_PC)
+ def = def*75/100;
+ //ストリップシールド時は減算
+ if(sc_data[SC_STRIPSHIELD].timer!=-1 && bl->type != BL_PC)
+ def = def*85/100;
+ //シグナムクルシス時は減算
+ if(sc_data[SC_SIGNUMCRUCIS].timer!=-1 && bl->type != BL_PC)
+ def = def * (100 - sc_data[SC_SIGNUMCRUCIS].val2)/100;
+ //永遠の混沌時はDEF0になる
+ if(sc_data[SC_ETERNALCHAOS].timer!=-1 && bl->type != BL_PC)
+ def = 0;
+ //凍結、石化時は右シフト
+ if(sc_data[SC_FREEZE].timer != -1 || (sc_data[SC_STONE].timer != -1 && sc_data[SC_STONE].val2 == 0))
+ def >>= 1;
+ //コンセントレーション時は減算
+ if( sc_data[SC_CONCENTRATION].timer!=-1 && bl->type != BL_PC)
+ def = (def*(100 - 5*sc_data[SC_CONCENTRATION].val1))/100;
+ }
+ //詠唱中は詠唱時減算率に基づいて減算
+ if(skilltimer != -1) {
+ int def_rate = skill_get_castdef(skillid);
+ if(def_rate != 0)
+ def = (def * (100 - def_rate))/100;
+ }
+ }
+ if(def < 0) def = 0;
+ return def;
+}
+/*==========================================
+ * 対象のMDefを返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_mdef(struct block_list *bl)
+{
+ struct status_change *sc_data;
+ int mdef=0;
+
+ nullpo_retr(0, bl);
+ sc_data=battle_get_sc_data(bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl)
+ mdef = ((struct map_session_data *)bl)->mdef;
+ else if(bl->type==BL_MOB && (struct mob_data *)bl)
+ mdef = mob_db[((struct mob_data *)bl)->class].mdef;
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ mdef = mob_db[((struct pet_data *)bl)->class].mdef;
+
+ if(mdef < 1000000) {
+ if(sc_data) {
+ //バリアー状態時はMDEF100
+ if(sc_data[SC_BARRIER].timer != -1)
+ mdef = 100;
+ //凍結、石化時は1.25倍
+ if(sc_data[SC_FREEZE].timer != -1 || (sc_data[SC_STONE].timer != -1 && sc_data[SC_STONE].val2 == 0))
+ mdef = mdef*125/100;
+ if( sc_data[SC_MINDBREAKER].timer!=-1 && bl->type != BL_PC)
+ mdef -= (mdef*6*sc_data[SC_MINDBREAKER].val1)/100;
+ }
+ }
+ if(mdef < 0) mdef = 0;
+ return mdef;
+}
+/*==========================================
+ * 対象のDef2を返す(汎用)
+ * 戻りは整数で1以上
+ *------------------------------------------
+ */
+int battle_get_def2(struct block_list *bl)
+{
+ struct status_change *sc_data;
+ int def2=1;
+
+ nullpo_retr(1, bl);
+ sc_data=battle_get_sc_data(bl);
+ if(bl->type==BL_PC)
+ def2 = ((struct map_session_data *)bl)->def2;
+ else if(bl->type==BL_MOB)
+ def2 = mob_db[((struct mob_data *)bl)->class].vit;
+ else if(bl->type==BL_PET)
+ def2 = mob_db[((struct pet_data *)bl)->class].vit;
+
+ if(sc_data) {
+ if( sc_data[SC_ANGELUS].timer!=-1 && bl->type != BL_PC)
+ def2 = def2*(110+5*sc_data[SC_ANGELUS].val1)/100;
+ if( sc_data[SC_PROVOKE].timer!=-1 && bl->type != BL_PC)
+ def2 = (def2*(100 - 6*sc_data[SC_PROVOKE].val1)+50)/100;
+ if(sc_data[SC_POISON].timer!=-1 && bl->type != BL_PC)
+ def2 = def2*75/100;
+ //コンセントレーション時は減算
+ if( sc_data[SC_CONCENTRATION].timer!=-1 && bl->type != BL_PC)
+ def2 = def2*(100 - 5*sc_data[SC_CONCENTRATION].val1)/100;
+ }
+ if(def2 < 1) def2 = 1;
+ return def2;
+}
+/*==========================================
+ * 対象のMDef2を返す(汎用)
+ * 戻りは整数で0以上
+ *------------------------------------------
+ */
+int battle_get_mdef2(struct block_list *bl)
+{
+ int mdef2=0;
+ struct status_change *sc_data=battle_get_sc_data(bl);
+
+ nullpo_retr(0, bl);
+ if(bl->type==BL_MOB)
+ mdef2 = mob_db[((struct mob_data *)bl)->class].int_ + (mob_db[((struct mob_data *)bl)->class].vit>>1);
+ else if(bl->type==BL_PC)
+ mdef2 = ((struct map_session_data *)bl)->mdef2 + (((struct map_session_data *)bl)->paramc[2]>>1);
+ else if(bl->type==BL_PET)
+ mdef2 = mob_db[((struct pet_data *)bl)->class].int_ + (mob_db[((struct pet_data *)bl)->class].vit>>1);
+ if(sc_data) {
+ if( sc_data[SC_MINDBREAKER].timer!=-1 && bl->type != BL_PC)
+ mdef2 -= (mdef2*6*sc_data[SC_MINDBREAKER].val1)/100;
+ }
+ if(mdef2 < 0) mdef2 = 0;
+ return mdef2;
+}
+/*==========================================
+ * 対象のSpeed(移動速度)を返す(汎用)
+ * 戻りは整数で1以上
+ * Speedは小さいほうが移動速度が速い
+ *------------------------------------------
+ */
+int battle_get_speed(struct block_list *bl)
+{
+ nullpo_retr(1000, bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return ((struct map_session_data *)bl)->speed;
+ else {
+ struct status_change *sc_data=battle_get_sc_data(bl);
+ int speed = 1000;
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+// speed = mob_db[((struct mob_data *)bl)->class].speed;
+ speed = ((struct mob_data *)bl)->speed;
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ speed = ((struct pet_data *)bl)->msd->petDB->speed;
+
+ if(sc_data) {
+ //速度増加時は25%減算
+ if(sc_data[SC_INCREASEAGI].timer!=-1 && sc_data[SC_DONTFORGETME].timer == -1)
+ speed -= speed*25/100;
+ //速度減少時は25%加算
+ if(sc_data[SC_DECREASEAGI].timer!=-1)
+ speed = speed*125/100;
+ //クァグマイア時は50%加算
+ if(sc_data[SC_QUAGMIRE].timer!=-1)
+ speed = speed*3/2;
+ //私を忘れないで…時は加算
+ if(sc_data[SC_DONTFORGETME].timer!=-1)
+ speed = speed*(100+sc_data[SC_DONTFORGETME].val1*2 + sc_data[SC_DONTFORGETME].val2 + (sc_data[SC_DONTFORGETME].val3&0xffff))/100;
+ //金剛時は25%加算
+ if(sc_data[SC_STEELBODY].timer!=-1)
+ speed = speed*125/100;
+ //ディフェンダー時は加算
+ if(sc_data[SC_DEFENDER].timer!=-1)
+ speed = (speed * (155 - sc_data[SC_DEFENDER].val1*5)) / 100;
+ //踊り状態は4倍遅い
+ if(sc_data[SC_DANCING].timer!=-1 )
+ speed*=4;
+ //呪い時は450加算
+ if(sc_data[SC_CURSE].timer!=-1)
+ speed = speed + 450;
+ //ウィンドウォーク時はLv*2%減算
+ if(sc_data[SC_WINDWALK].timer!=-1)
+ speed -= (speed*(sc_data[SC_WINDWALK].val1*2))/100;
+ }
+ if(speed < 1) speed = 1;
+ return speed;
+ }
+
+ return 1000;
+}
+/*==========================================
+ * 対象のaDelay(攻撃時ディレイ)を返す(汎用)
+ * aDelayは小さいほうが攻撃速度が速い
+ *------------------------------------------
+ */
+int battle_get_adelay(struct block_list *bl)
+{
+ nullpo_retr(4000, bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return (((struct map_session_data *)bl)->aspd<<1);
+ else {
+ struct status_change *sc_data=battle_get_sc_data(bl);
+ int adelay=4000,aspd_rate = 100,i;
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ adelay = mob_db[((struct mob_data *)bl)->class].adelay;
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ adelay = mob_db[((struct pet_data *)bl)->class].adelay;
+
+ if(sc_data) {
+ //ツーハンドクイッケン使用時でクァグマイアでも私を忘れないで…でもない時は3割減算
+ if(sc_data[SC_TWOHANDQUICKEN].timer != -1 && sc_data[SC_QUAGMIRE].timer == -1 && sc_data[SC_DONTFORGETME].timer == -1) // 2HQ
+ aspd_rate -= 30;
+ //アドレナリンラッシュ使用時でツーハンドクイッケンでもクァグマイアでも私を忘れないで…でもない時は
+ if(sc_data[SC_ADRENALINE].timer != -1 && sc_data[SC_TWOHANDQUICKEN].timer == -1 &&
+ sc_data[SC_QUAGMIRE].timer == -1 && sc_data[SC_DONTFORGETME].timer == -1) { // アドレナリンラッシュ
+ //使用者とパーティメンバーで格差が出る設定でなければ3割減算
+ if(sc_data[SC_ADRENALINE].val2 || !battle_config.party_skill_penaly)
+ aspd_rate -= 30;
+ //そうでなければ2.5割減算
+ else
+ aspd_rate -= 25;
+ }
+ //スピアクィッケン時は減算
+ if(sc_data[SC_SPEARSQUICKEN].timer != -1 && sc_data[SC_ADRENALINE].timer == -1 &&
+ sc_data[SC_TWOHANDQUICKEN].timer == -1 && sc_data[SC_QUAGMIRE].timer == -1 && sc_data[SC_DONTFORGETME].timer == -1) // スピアクィッケン
+ aspd_rate -= sc_data[SC_SPEARSQUICKEN].val2;
+ //夕日のアサシンクロス時は減算
+ if(sc_data[SC_ASSNCROS].timer!=-1 && // 夕陽のアサシンクロス
+ sc_data[SC_TWOHANDQUICKEN].timer==-1 && sc_data[SC_ADRENALINE].timer==-1 && sc_data[SC_SPEARSQUICKEN].timer==-1 &&
+ sc_data[SC_DONTFORGETME].timer == -1)
+ aspd_rate -= 5+sc_data[SC_ASSNCROS].val1+sc_data[SC_ASSNCROS].val2+sc_data[SC_ASSNCROS].val3;
+ //私を忘れないで…時は加算
+ if(sc_data[SC_DONTFORGETME].timer!=-1) // 私を忘れないで
+ aspd_rate += sc_data[SC_DONTFORGETME].val1*3 + sc_data[SC_DONTFORGETME].val2 + (sc_data[SC_DONTFORGETME].val3>>16);
+ //金剛時25%加算
+ if(sc_data[SC_STEELBODY].timer!=-1) // 金剛
+ aspd_rate += 25;
+ //増速ポーション使用時は減算
+ if( sc_data[i=SC_SPEEDPOTION2].timer!=-1 || sc_data[i=SC_SPEEDPOTION1].timer!=-1 || sc_data[i=SC_SPEEDPOTION0].timer!=-1)
+ aspd_rate -= sc_data[i].val2;
+ //ディフェンダー時は加算
+ if(sc_data[SC_DEFENDER].timer != -1)
+ adelay += (1100 - sc_data[SC_DEFENDER].val1*100);
+ }
+ if(aspd_rate != 100)
+ adelay = adelay*aspd_rate/100;
+ if(adelay < battle_config.monster_max_aspd<<1) adelay = battle_config.monster_max_aspd<<1;
+ return adelay;
+ }
+ return 4000;
+}
+int battle_get_amotion(struct block_list *bl)
+{
+ nullpo_retr(2000, bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return ((struct map_session_data *)bl)->amotion;
+ else {
+ struct status_change *sc_data=battle_get_sc_data(bl);
+ int amotion=2000,aspd_rate = 100,i;
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ amotion = mob_db[((struct mob_data *)bl)->class].amotion;
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ amotion = mob_db[((struct pet_data *)bl)->class].amotion;
+
+ if(sc_data) {
+ if(sc_data[SC_TWOHANDQUICKEN].timer != -1 && sc_data[SC_QUAGMIRE].timer == -1 && sc_data[SC_DONTFORGETME].timer == -1) // 2HQ
+ aspd_rate -= 30;
+ if(sc_data[SC_ADRENALINE].timer != -1 && sc_data[SC_TWOHANDQUICKEN].timer == -1 &&
+ sc_data[SC_QUAGMIRE].timer == -1 && sc_data[SC_DONTFORGETME].timer == -1) { // アドレナリンラッシュ
+ if(sc_data[SC_ADRENALINE].val2 || !battle_config.party_skill_penaly)
+ aspd_rate -= 30;
+ else
+ aspd_rate -= 25;
+ }
+ if(sc_data[SC_SPEARSQUICKEN].timer != -1 && sc_data[SC_ADRENALINE].timer == -1 &&
+ sc_data[SC_TWOHANDQUICKEN].timer == -1 && sc_data[SC_QUAGMIRE].timer == -1 && sc_data[SC_DONTFORGETME].timer == -1) // スピアクィッケン
+ aspd_rate -= sc_data[SC_SPEARSQUICKEN].val2;
+ if(sc_data[SC_ASSNCROS].timer!=-1 && // 夕陽のアサシンクロス
+ sc_data[SC_TWOHANDQUICKEN].timer==-1 && sc_data[SC_ADRENALINE].timer==-1 && sc_data[SC_SPEARSQUICKEN].timer==-1 &&
+ sc_data[SC_DONTFORGETME].timer == -1)
+ aspd_rate -= 5+sc_data[SC_ASSNCROS].val1+sc_data[SC_ASSNCROS].val2+sc_data[SC_ASSNCROS].val3;
+ if(sc_data[SC_DONTFORGETME].timer!=-1) // 私を忘れないで
+ aspd_rate += sc_data[SC_DONTFORGETME].val1*3 + sc_data[SC_DONTFORGETME].val2 + (sc_data[SC_DONTFORGETME].val3>>16);
+ if(sc_data[SC_STEELBODY].timer!=-1) // 金剛
+ aspd_rate += 25;
+ if( sc_data[i=SC_SPEEDPOTION2].timer!=-1 || sc_data[i=SC_SPEEDPOTION1].timer!=-1 || sc_data[i=SC_SPEEDPOTION0].timer!=-1)
+ aspd_rate -= sc_data[i].val2;
+ if(sc_data[SC_DEFENDER].timer != -1)
+ amotion += (550 - sc_data[SC_DEFENDER].val1*50);
+ }
+ if(aspd_rate != 100)
+ amotion = amotion*aspd_rate/100;
+ if(amotion < battle_config.monster_max_aspd) amotion = battle_config.monster_max_aspd;
+ return amotion;
+ }
+ return 2000;
+}
+int battle_get_dmotion(struct block_list *bl)
+{
+ int ret;
+ struct status_change *sc_data;
+
+ nullpo_retr(0, bl);
+ sc_data = battle_get_sc_data(bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl){
+ ret=mob_db[((struct mob_data *)bl)->class].dmotion;
+ if(battle_config.monster_damage_delay_rate != 100)
+ ret = ret*battle_config.monster_damage_delay_rate/400;
+ }
+ else if(bl->type==BL_PC && (struct map_session_data *)bl){
+ ret=((struct map_session_data *)bl)->dmotion;
+ if(battle_config.pc_damage_delay_rate != 100)
+ ret = ret*battle_config.pc_damage_delay_rate/400;
+ }
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ ret=mob_db[((struct pet_data *)bl)->class].dmotion;
+ else
+ return 2000;
+
+ if((sc_data && sc_data[SC_ENDURE].timer!=-1) ||
+ (bl->type == BL_PC && ((struct map_session_data *)bl)->special_state.infinite_endure))
+ ret=0;
+
+ return ret;
+}
+int battle_get_element(struct block_list *bl)
+{
+ int ret = 20;
+ struct status_change *sc_data;
+
+ nullpo_retr(ret, bl);
+ sc_data = battle_get_sc_data(bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl) // 10の位=Lv*2、1の位=属性
+ ret=((struct mob_data *)bl)->def_ele;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ ret=20+((struct map_session_data *)bl)->def_ele; // 防御属性Lv1
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ ret = mob_db[((struct pet_data *)bl)->class].element;
+
+ if(sc_data) {
+ if( sc_data[SC_BENEDICTIO].timer!=-1 ) // 聖体降福
+ ret=26;
+ if( sc_data[SC_FREEZE].timer!=-1 ) // 凍結
+ ret=21;
+ if( sc_data[SC_STONE].timer!=-1 && sc_data[SC_STONE].val2==0)
+ ret=22;
+ }
+
+ return ret;
+}
+int battle_get_attack_element(struct block_list *bl)
+{
+ int ret = 0;
+ struct status_change *sc_data=battle_get_sc_data(bl);
+
+ nullpo_retr(0, bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ ret=0;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ ret=((struct map_session_data *)bl)->atk_ele;
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ ret=0;
+
+ if(sc_data) {
+ if( sc_data[SC_FROSTWEAPON].timer!=-1) // フロストウェポン
+ ret=1;
+ if( sc_data[SC_SEISMICWEAPON].timer!=-1) // サイズミックウェポン
+ ret=2;
+ if( sc_data[SC_FLAMELAUNCHER].timer!=-1) // フレームランチャー
+ ret=3;
+ if( sc_data[SC_LIGHTNINGLOADER].timer!=-1) // ライトニングローダー
+ ret=4;
+ if( sc_data[SC_ENCPOISON].timer!=-1) // エンチャントポイズン
+ ret=5;
+ if( sc_data[SC_ASPERSIO].timer!=-1) // アスペルシオ
+ ret=6;
+ }
+
+ return ret;
+}
+int battle_get_attack_element2(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl) {
+ int ret = ((struct map_session_data *)bl)->atk_ele_;
+ struct status_change *sc_data = ((struct map_session_data *)bl)->sc_data;
+
+ if(sc_data) {
+ if( sc_data[SC_FROSTWEAPON].timer!=-1) // フロストウェポン
+ ret=1;
+ if( sc_data[SC_SEISMICWEAPON].timer!=-1) // サイズミックウェポン
+ ret=2;
+ if( sc_data[SC_FLAMELAUNCHER].timer!=-1) // フレームランチャー
+ ret=3;
+ if( sc_data[SC_LIGHTNINGLOADER].timer!=-1) // ライトニングローダー
+ ret=4;
+ if( sc_data[SC_ENCPOISON].timer!=-1) // エンチャントポイズン
+ ret=5;
+ if( sc_data[SC_ASPERSIO].timer!=-1) // アスペルシオ
+ ret=6;
+ }
+ return ret;
+ }
+ return 0;
+}
+int battle_get_party_id(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return ((struct map_session_data *)bl)->status.party_id;
+ else if(bl->type==BL_MOB && (struct mob_data *)bl){
+ struct mob_data *md=(struct mob_data *)bl;
+ if( md->master_id>0 )
+ return -md->master_id;
+ return -md->bl.id;
+ }
+ else if(bl->type==BL_SKILL && (struct skill_unit *)bl)
+ return ((struct skill_unit *)bl)->group->party_id;
+ else
+ return 0;
+}
+int battle_get_guild_id(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return ((struct map_session_data *)bl)->status.guild_id;
+ else if(bl->type==BL_MOB && (struct mob_data *)bl)
+ return ((struct mob_data *)bl)->class;
+ else if(bl->type==BL_SKILL && (struct skill_unit *)bl)
+ return ((struct skill_unit *)bl)->group->guild_id;
+ else
+ return 0;
+}
+int battle_get_race(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ return mob_db[((struct mob_data *)bl)->class].race;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return 7;
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ return mob_db[((struct pet_data *)bl)->class].race;
+ else
+ return 0;
+}
+int battle_get_size(struct block_list *bl)
+{
+ nullpo_retr(1, bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ return mob_db[((struct mob_data *)bl)->class].size;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return 1;
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ return mob_db[((struct pet_data *)bl)->class].size;
+ else
+ return 1;
+}
+int battle_get_mode(struct block_list *bl)
+{
+ nullpo_retr(0x01, bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ return mob_db[((struct mob_data *)bl)->class].mode;
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ return mob_db[((struct pet_data *)bl)->class].mode;
+ else
+ return 0x01; // とりあえず動くということで1
+}
+
+int battle_get_mexp(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ return mob_db[((struct mob_data *)bl)->class].mexp;
+ else if(bl->type==BL_PET && (struct pet_data *)bl)
+ return mob_db[((struct pet_data *)bl)->class].mexp;
+ else
+ return 0;
+}
+
+// StatusChange系の所得
+struct status_change *battle_get_sc_data(struct block_list *bl)
+{
+ nullpo_retr(NULL, bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ return ((struct mob_data*)bl)->sc_data;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return ((struct map_session_data*)bl)->sc_data;
+ return NULL;
+}
+short *battle_get_sc_count(struct block_list *bl)
+{
+ nullpo_retr(NULL, bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ return &((struct mob_data*)bl)->sc_count;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return &((struct map_session_data*)bl)->sc_count;
+ return NULL;
+}
+short *battle_get_opt1(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ return &((struct mob_data*)bl)->opt1;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return &((struct map_session_data*)bl)->opt1;
+ else if(bl->type==BL_NPC && (struct npc_data *)bl)
+ return &((struct npc_data*)bl)->opt1;
+ return 0;
+}
+short *battle_get_opt2(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ return &((struct mob_data*)bl)->opt2;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return &((struct map_session_data*)bl)->opt2;
+ else if(bl->type==BL_NPC && (struct npc_data *)bl)
+ return &((struct npc_data*)bl)->opt2;
+ return 0;
+}
+short *battle_get_opt3(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ return &((struct mob_data*)bl)->opt3;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return &((struct map_session_data*)bl)->opt3;
+ else if(bl->type==BL_NPC && (struct npc_data *)bl)
+ return &((struct npc_data*)bl)->opt3;
+ return 0;
+}
+short *battle_get_option(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_MOB && (struct mob_data *)bl)
+ return &((struct mob_data*)bl)->option;
+ else if(bl->type==BL_PC && (struct map_session_data *)bl)
+ return &((struct map_session_data*)bl)->status.option;
+ else if(bl->type==BL_NPC && (struct npc_data *)bl)
+ return &((struct npc_data*)bl)->option;
+ return 0;
+}
+
+//-------------------------------------------------------------------
+
+// ダメージの遅延
+struct battle_delay_damage_ {
+ struct block_list *src,*target;
+ int damage;
+ int flag;
+};
+int battle_delay_damage_sub(int tid,unsigned int tick,int id,int data)
+{
+ struct battle_delay_damage_ *dat=(struct battle_delay_damage_ *)data;
+ if( dat && map_id2bl(id)==dat->src && dat->target->prev!=NULL)
+ battle_damage(dat->src,dat->target,dat->damage,dat->flag);
+ free(dat);
+ return 0;
+}
+int battle_delay_damage(unsigned int tick,struct block_list *src,struct block_list *target,int damage,int flag)
+{
+ struct battle_delay_damage_ *dat = (struct battle_delay_damage_*)aCalloc(1,sizeof(struct battle_delay_damage_));
+
+ nullpo_retr(0, src);
+ nullpo_retr(0, target);
+
+
+ dat->src=src;
+ dat->target=target;
+ dat->damage=damage;
+ dat->flag=flag;
+ add_timer(tick,battle_delay_damage_sub,src->id,(int)dat);
+ return 0;
+}
+
+// 実際にHPを操作
+int battle_damage(struct block_list *bl,struct block_list *target,int damage,int flag)
+{
+ struct map_session_data *sd=NULL;
+ struct status_change *sc_data=battle_get_sc_data(target);
+ short *sc_count;
+ int i;
+
+ nullpo_retr(0, target); //blはNULLで呼ばれることがあるので他でチェック
+
+ if(damage==0 || target->type == BL_PET)
+ return 0;
+
+ if(target->prev == NULL)
+ return 0;
+
+ if(bl) {
+ if(bl->prev==NULL)
+ return 0;
+
+ if(bl->type==BL_PC)
+ sd=(struct map_session_data *)bl;
+ }
+
+ if(damage<0)
+ return battle_heal(bl,target,-damage,0,flag);
+
+ if(!flag && (sc_count=battle_get_sc_count(target))!=NULL && *sc_count>0){
+ // 凍結、石化、睡眠を消去
+ if(sc_data[SC_FREEZE].timer!=-1)
+ skill_status_change_end(target,SC_FREEZE,-1);
+ if(sc_data[SC_STONE].timer!=-1 && sc_data[SC_STONE].val2==0)
+ skill_status_change_end(target,SC_STONE,-1);
+ if(sc_data[SC_SLEEP].timer!=-1)
+ skill_status_change_end(target,SC_SLEEP,-1);
+ }
+
+ if(target->type==BL_MOB){ // MOB
+ struct mob_data *md=(struct mob_data *)target;
+ if(md && md->skilltimer!=-1 && md->state.skillcastcancel) // 詠唱妨害
+ skill_castcancel(target,0);
+ return mob_damage(bl,md,damage,0);
+ }
+ else if(target->type==BL_PC){ // PC
+
+ struct map_session_data *tsd=(struct map_session_data *)target;
+
+ if(tsd && tsd->sc_data && tsd->sc_data[SC_DEVOTION].val1){ // ディボーションをかけられている
+ struct map_session_data *md = map_id2sd(tsd->sc_data[SC_DEVOTION].val1);
+ if(md && skill_devotion3(&md->bl,target->id)){
+ skill_devotion(md,target->id);
+ }
+ else if(md && bl)
+ for(i=0;i<5;i++)
+ if(md->dev.val1[i] == target->id){
+ clif_damage(bl,&md->bl, gettick(), 0, 0,
+ damage, 0 , 0, 0);
+ pc_damage(&md->bl,md,damage);
+
+ return 0;
+ }
+ }
+
+ if(tsd && tsd->skilltimer!=-1){ // 詠唱妨害
+ // フェンカードや妨害されないスキルかの検査
+ if( (!tsd->special_state.no_castcancel || map[bl->m].flag.gvg) && tsd->state.skillcastcancel &&
+ !tsd->special_state.no_castcancel2)
+ skill_castcancel(target,0);
+ }
+
+ return pc_damage(bl,tsd,damage);
+
+ }
+ else if(target->type==BL_SKILL)
+ return skill_unit_ondamaged((struct skill_unit *)target,bl,damage,gettick());
+ return 0;
+}
+int battle_heal(struct block_list *bl,struct block_list *target,int hp,int sp,int flag)
+{
+ nullpo_retr(0, target); //blはNULLで呼ばれることがあるので他でチェック
+
+ if(target->type == BL_PET)
+ return 0;
+ if( target->type ==BL_PC && pc_isdead((struct map_session_data *)target) )
+ return 0;
+ if(hp==0 && sp==0)
+ return 0;
+
+ if(hp<0)
+ return battle_damage(bl,target,-hp,flag);
+
+ if(target->type==BL_MOB)
+ return mob_heal((struct mob_data *)target,hp);
+ else if(target->type==BL_PC)
+ return pc_heal((struct map_session_data *)target,hp,sp);
+ return 0;
+}
+
+// 攻撃停止
+int battle_stopattack(struct block_list *bl)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_MOB)
+ return mob_stopattack((struct mob_data*)bl);
+ else if(bl->type==BL_PC)
+ return pc_stopattack((struct map_session_data*)bl);
+ else if(bl->type==BL_PET)
+ return pet_stopattack((struct pet_data*)bl);
+ return 0;
+}
+// 移動停止
+int battle_stopwalking(struct block_list *bl,int type)
+{
+ nullpo_retr(0, bl);
+ if(bl->type==BL_MOB)
+ return mob_stop_walking((struct mob_data*)bl,type);
+ else if(bl->type==BL_PC)
+ return pc_stop_walking((struct map_session_data*)bl,type);
+ else if(bl->type==BL_PET)
+ return pet_stop_walking((struct pet_data*)bl,type);
+ return 0;
+}
+
+
+/*==========================================
+ * ダメージの属性修正
+ *------------------------------------------
+ */
+int battle_attr_fix(int damage,int atk_elem,int def_elem)
+{
+ int def_type= def_elem%10, def_lv=def_elem/10/2;
+
+ if( atk_elem<0 || atk_elem>9 || def_type<0 || def_type>9 ||
+ def_lv<1 || def_lv>4){ // 属 性値がおかしいのでとりあえずそのまま返す
+ if(battle_config.error_log)
+ printf("battle_attr_fix: unknown attr type: atk=%d def_type=%d def_lv=%d\n",atk_elem,def_type,def_lv);
+ return damage;
+ }
+
+ return damage*attr_fix_table[def_lv-1][atk_elem][def_type]/100;
+}
+
+
+/*==========================================
+ * ダメージ最終計算
+ *------------------------------------------
+ */
+int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,int div_,int skill_num,int skill_lv,int flag)
+{
+ struct map_session_data *sd=NULL;
+ struct mob_data *md=NULL;
+ struct status_change *sc_data,*sc;
+ short *sc_count;
+ int class;
+
+ nullpo_retr(0, bl);
+
+ class = battle_get_class(bl);
+ if(bl->type==BL_MOB) md=(struct mob_data *)bl;
+ else sd=(struct map_session_data *)bl;
+
+ sc_data=battle_get_sc_data(bl);
+ sc_count=battle_get_sc_count(bl);
+
+ if(sc_count!=NULL && *sc_count>0){
+
+ if(sc_data[SC_SAFETYWALL].timer!=-1 && damage>0 && flag&BF_WEAPON && flag&BF_SHORT && skill_num != NPC_GUIDEDATTACK){
+ // セーフティウォール
+ struct skill_unit *unit=(struct skill_unit*)sc_data[SC_SAFETYWALL].val2;
+ if( unit && unit->alive && (--unit->group->val2)<=0 )
+ skill_delunit(unit);
+ skill_unit_move(bl,gettick(),1); // 重ね掛けチェック
+ damage=0;
+ }
+ if(sc_data[SC_PNEUMA].timer!=-1 && damage>0 && flag&BF_WEAPON && flag&BF_LONG && skill_num != NPC_GUIDEDATTACK){
+ // ニューマ
+ damage=0;
+ }
+
+ if(sc_data[SC_ROKISWEIL].timer!=-1 && damage>0 &&
+ flag&BF_MAGIC ){
+ // ニューマ
+ damage=0;
+ }
+
+ if(sc_data[SC_AETERNA].timer!=-1 && damage>0){ // レックスエーテルナ
+ damage<<=1;
+ skill_status_change_end( bl,SC_AETERNA,-1 );
+ }
+
+ //属性場のダメージ増加
+ if(sc_data[SC_VOLCANO].timer!=-1){ // ボルケーノ
+ if(flag&BF_SKILL && skill_get_pl(skill_num)==3)
+ damage += damage*sc_data[SC_VOLCANO].val4/100;
+ else if(!flag&BF_SKILL && battle_get_attack_element(bl)==3)
+ damage += damage*sc_data[SC_VOLCANO].val4/100;
+ }
+
+ if(sc_data[SC_VIOLENTGALE].timer!=-1){ // バイオレントゲイル
+ if(flag&BF_SKILL && skill_get_pl(skill_num)==4)
+ damage += damage*sc_data[SC_VIOLENTGALE].val4/100;
+ else if(!flag&BF_SKILL && battle_get_attack_element(bl)==4)
+ damage += damage*sc_data[SC_VIOLENTGALE].val4/100;
+ }
+
+ if(sc_data[SC_DELUGE].timer!=-1){ // デリュージ
+ if(flag&BF_SKILL && skill_get_pl(skill_num)==1)
+ damage += damage*sc_data[SC_DELUGE].val4/100;
+ else if(!flag&BF_SKILL && battle_get_attack_element(bl)==1)
+ damage += damage*sc_data[SC_DELUGE].val4/100;
+ }
+
+ if(sc_data[SC_ENERGYCOAT].timer!=-1 && damage>0 && flag&BF_WEAPON){ // エナジーコート
+ if(sd){
+ if(sd->status.sp>0){
+ int per = sd->status.sp * 5 / (sd->status.max_sp + 1);
+ sd->status.sp -= sd->status.sp * (per * 5 + 10) / 1000;
+ if( sd->status.sp < 0 ) sd->status.sp = 0;
+ damage -= damage * ((per+1) * 6) / 100;
+ clif_updatestatus(sd,SP_SP);
+ }
+ if(sd->status.sp<=0)
+ skill_status_change_end( bl,SC_ENERGYCOAT,-1 );
+ }
+ else
+ damage -= damage * (sc_data[SC_ENERGYCOAT].val1 * 6) / 100;
+ }
+
+ if(sc_data[SC_KYRIE].timer!=-1 && damage > 0){ // キリエエレイソン
+ sc=&sc_data[SC_KYRIE];
+ sc->val2-=damage;
+ if(flag&BF_WEAPON){
+ if(sc->val2>=0) damage=0;
+ else damage=-sc->val2;
+ }
+ if((--sc->val3)<=0 || (sc->val2<=0) || skill_num == AL_HOLYLIGHT)
+ skill_status_change_end(bl, SC_KYRIE, -1);
+ }
+
+ if(sc_data[SC_BASILICA].timer!=-1 && damage > 0){
+ // ニューマ
+ damage=0;
+ }
+ if(sc_data[SC_LANDPROTECTOR].timer!=-1 && damage>0 && flag&BF_MAGIC){
+ // ニューマ
+ damage=0;
+ }
+
+ if(sc_data[SC_AUTOGUARD].timer != -1 && damage > 0 && flag&BF_WEAPON) {
+ if(rand()%100 < sc_data[SC_AUTOGUARD].val2) {
+ damage = 0;
+ clif_skill_nodamage(bl,bl,CR_AUTOGUARD,sc_data[SC_AUTOGUARD].val1,1);
+ if(sd)
+ sd->canmove_tick = gettick() + 300;
+ else if(md)
+ md->canmove_tick = gettick() + 300;
+ }
+ }
+// -- moonsoul (chance to block attacks with new Lord Knight skill parrying)
+//
+ if(sc_data[SC_PARRYING].timer != -1 && damage > 0 && flag&BF_WEAPON) {
+ if(rand()%100 < sc_data[SC_PARRYING].val2) {
+ damage = 0;
+ clif_skill_nodamage(bl,bl,LK_PARRYING,sc_data[SC_PARRYING].val1,1);
+ }
+ }
+ // リジェクトソード
+ if(sc_data[SC_REJECTSWORD].timer!=-1 && damage > 0 && flag&BF_WEAPON &&
+ ((src->type==BL_PC && ((struct map_session_data *)src)->status.weapon == (1 || 2 || 3)) || src->type==BL_MOB )){
+ if(rand()%100 < (10+5*sc_data[SC_REJECTSWORD].val1)){ //反射確率は10+5*Lv
+ damage = damage*50/100;
+ battle_damage(bl,src,damage,0);
+ //ダメージを与えたのは良いんだが、ここからどうして表示するんだかわかんねぇ
+ //エフェクトもこれでいいのかわかんねぇ
+ clif_skill_nodamage(bl,bl,ST_REJECTSWORD,sc_data[SC_REJECTSWORD].val1,1);
+ if((--sc_data[SC_REJECTSWORD].val2)<=0)
+ skill_status_change_end(bl, SC_REJECTSWORD, -1);
+ }
+ }
+ }
+
+ if(class == 1288 || class == 1287 || class == 1286 || class == 1285) {
+// if(class == 1288) {
+ if(class == 1288 && flag&BF_SKILL)
+ damage=0;
+ if(src->type == BL_PC) {
+ struct guild *g=guild_search(((struct map_session_data *)src)->status.guild_id);
+ struct guild_castle *gc=guild_mapname2gc(map[bl->m].name);
+ if(!((struct map_session_data *)src)->status.guild_id)
+ damage=0;
+ if(gc && agit_flag==0 && class != 1288) // guardians cannot be damaged during non-woe [Valaris]
+ damage=0; // end woe check [Valaris]
+ if(g == NULL)
+ damage=0;//ギルド未加入ならダメージ無し
+ else if((gc != NULL) && guild_isallied(g, gc))
+ damage=0;//自占領ギルドのエンペならダメージ無し
+ else if(g && guild_checkskill(g,GD_APPROVAL) <= 0)
+ damage=0;//正規ギルド承認がないとダメージ無し
+ else if (battle_config.guild_max_castles != 0 && guild_checkcastles(g)>=battle_config.guild_max_castles)
+ damage = 0; // [MouseJstr]
+ }
+ else damage = 0;
+ }
+
+ if(map[bl->m].flag.gvg && damage > 0) { //GvG
+ if(flag&BF_WEAPON) {
+ if(flag&BF_SHORT)
+ damage=damage*battle_config.gvg_short_damage_rate/100;
+ if(flag&BF_LONG)
+ damage=damage*battle_config.gvg_long_damage_rate/100;
+ }
+ if(flag&BF_MAGIC)
+ damage = damage*battle_config.gvg_magic_damage_rate/100;
+ if(flag&BF_MISC)
+ damage=damage*battle_config.gvg_misc_damage_rate/100;
+ if(damage < 1) damage = 1;
+ }
+
+ if(battle_config.skill_min_damage || flag&BF_MISC) {
+ if(div_ < 255) {
+ if(damage > 0 && damage < div_)
+ damage = div_;
+ }
+ else if(damage > 0 && damage < 3)
+ damage = 3;
+ }
+
+ if( md!=NULL && md->hp>0 && damage > 0 ) // 反撃などのMOBスキル判定
+ mobskill_event(md,flag);
+
+ return damage;
+}
+
+/*==========================================
+ * 修練ダメージ
+ *------------------------------------------
+ */
+int battle_addmastery(struct map_session_data *sd,struct block_list *target,int dmg,int type)
+{
+ int damage,skill;
+ int race=battle_get_race(target);
+ int weapon;
+ damage = 0;
+
+ nullpo_retr(0, sd);
+
+ // デーモンベイン(+3 〜 +30) vs 不死 or 悪魔 (死人は含めない?)
+ if((skill = pc_checkskill(sd,AL_DEMONBANE)) > 0 && (battle_check_undead(race,battle_get_elem_type(target)) || race==6) )
+ damage += (skill * 3);
+
+ // ビーストベイン(+4 〜 +40) vs 動物 or 昆虫
+ if((skill = pc_checkskill(sd,HT_BEASTBANE)) > 0 && (race==2 || race==4) )
+ damage += (skill * 4);
+
+ if(type == 0)
+ weapon = sd->weapontype1;
+ else
+ weapon = sd->weapontype2;
+ switch(weapon)
+ {
+ case 0x01: // 短剣 (Updated By AppleGirl)
+ case 0x02: // 1HS
+ {
+ // 剣修練(+4 〜 +40) 片手剣 短剣含む
+ if((skill = pc_checkskill(sd,SM_SWORD)) > 0) {
+ damage += (skill * 4);
+ }
+ break;
+ }
+ case 0x03: // 2HS
+ {
+ // 両手剣修練(+4 〜 +40) 両手剣
+ if((skill = pc_checkskill(sd,SM_TWOHAND)) > 0) {
+ damage += (skill * 4);
+ }
+ break;
+ }
+ case 0x04: // 1HL
+ {
+ // 槍修練(+4 〜 +40,+5 〜 +50) 槍
+ if((skill = pc_checkskill(sd,KN_SPEARMASTERY)) > 0) {
+ if(!pc_isriding(sd))
+ damage += (skill * 4); // ペコに乗ってない
+ else
+ damage += (skill * 5); // ペコに乗ってる
+ }
+ break;
+ }
+ case 0x05: // 2HL
+ {
+ // 槍修練(+4 〜 +40,+5 〜 +50) 槍
+ if((skill = pc_checkskill(sd,KN_SPEARMASTERY)) > 0) {
+ if(!pc_isriding(sd))
+ damage += (skill * 4); // ペコに乗ってない
+ else
+ damage += (skill * 5); // ペコに乗ってる
+ }
+ break;
+ }
+ case 0x06: // 片手斧
+ {
+ if((skill = pc_checkskill(sd,AM_AXEMASTERY)) > 0) {
+ damage += (skill * 3);
+ }
+ break;
+ }
+ case 0x07: // Axe by Tato
+ {
+ if((skill = pc_checkskill(sd,AM_AXEMASTERY)) > 0) {
+ damage += (skill * 3);
+ }
+ break;
+ }
+ case 0x08: // メイス
+ {
+ // メイス修練(+3 〜 +30) メイス
+ if((skill = pc_checkskill(sd,PR_MACEMASTERY)) > 0) {
+ damage += (skill * 3);
+ }
+ break;
+ }
+ case 0x09: // なし?
+ break;
+ case 0x0a: // 杖
+ break;
+ case 0x0b: // 弓
+ break;
+ case 0x00: // 素手
+ case 0x0c: // Knuckles
+ {
+ // 鉄拳(+3 〜 +30) 素手,ナックル
+ if((skill = pc_checkskill(sd,MO_IRONHAND)) > 0) {
+ damage += (skill * 3);
+ }
+ break;
+ }
+ case 0x0d: // Musical Instrument
+ {
+ // 楽器の練習(+3 〜 +30) 楽器
+ if((skill = pc_checkskill(sd,BA_MUSICALLESSON)) > 0) {
+ damage += (skill * 3);
+ }
+ break;
+ }
+ case 0x0e: // Dance Mastery
+ {
+ // Dance Lesson Skill Effect(+3 damage for every lvl = +30) 鞭
+ if((skill = pc_checkskill(sd,DC_DANCINGLESSON)) > 0) {
+ damage += (skill * 3);
+ }
+ break;
+ }
+ case 0x0f: // Book
+ {
+ // Advance Book Skill Effect(+3 damage for every lvl = +30) {
+ if((skill = pc_checkskill(sd,SA_ADVANCEDBOOK)) > 0) {
+ damage += (skill * 3);
+ }
+ break;
+ }
+ case 0x10: // Katars
+ {
+ // カタール修練(+3 〜 +30) カタール
+ if((skill = pc_checkskill(sd,AS_KATAR)) > 0) {
+ //ソニックブロー時は別処理(1撃に付き1/8適応)
+ damage += (skill * 3);
+ }
+ break;
+ }
+ }
+ damage = dmg + damage;
+ return (damage);
+}
+
+static struct Damage battle_calc_pet_weapon_attack(
+ struct block_list *src,struct block_list *target,int skill_num,int skill_lv,int wflag)
+{
+ struct pet_data *pd = (struct pet_data *)src;
+ struct mob_data *tmd=NULL;
+ int hitrate,flee,cri = 0,atkmin,atkmax;
+ int luk,target_count = 1;
+ int def1 = battle_get_def(target);
+ int def2 = battle_get_def2(target);
+ int t_vit = battle_get_vit(target);
+ struct Damage wd;
+ int damage,damage2=0,type,div_,blewcount=skill_get_blewcount(skill_num,skill_lv);
+ int flag,dmg_lv=0;
+ int t_mode=0,t_race=0,t_size=1,s_race=0,s_ele=0;
+ struct status_change *t_sc_data;
+
+ //return前の処理があるので情報出力部のみ変更
+ if( target == NULL || pd == NULL ){ //srcは内容に直接触れていないのでスルーしてみる
+ nullpo_info(NLP_MARK);
+ memset(&wd,0,sizeof(wd));
+ return wd;
+ }
+
+ s_race=battle_get_race(src);
+ s_ele=battle_get_attack_element(src);
+
+ // ターゲット
+ if(target->type == BL_MOB)
+ tmd=(struct mob_data *)target;
+ else {
+ memset(&wd,0,sizeof(wd));
+ return wd;
+ }
+ t_race=battle_get_race( target );
+ t_size=battle_get_size( target );
+ t_mode=battle_get_mode( target );
+ t_sc_data=battle_get_sc_data( target );
+
+ flag=BF_SHORT|BF_WEAPON|BF_NORMAL; // 攻撃の種類の設定
+
+ // 回避率計算、回避判定は後で
+ flee = battle_get_flee(target);
+ if(battle_config.agi_penaly_type > 0 || battle_config.vit_penaly_type > 0)
+ target_count += battle_counttargeted(target,src,battle_config.agi_penaly_count_lv);
+ if(battle_config.agi_penaly_type > 0) {
+ if(target_count >= battle_config.agi_penaly_count) {
+ if(battle_config.agi_penaly_type == 1)
+ flee = (flee * (100 - (target_count - (battle_config.agi_penaly_count - 1))*battle_config.agi_penaly_num))/100;
+ else if(battle_config.agi_penaly_type == 2)
+ flee -= (target_count - (battle_config.agi_penaly_count - 1))*battle_config.agi_penaly_num;
+ if(flee < 1) flee = 1;
+ }
+ }
+ hitrate=battle_get_hit(src) - flee + 80;
+
+ type=0; // normal
+ div_ = 1; // single attack
+
+ luk=battle_get_luk(src);
+
+ if(battle_config.pet_str)
+ damage = battle_get_baseatk(src);
+ else
+ damage = 0;
+
+ if(skill_num==HW_MAGICCRASHER){ /* マジッククラッシャーはMATKで殴る */
+ atkmin = battle_get_matk1(src);
+ atkmax = battle_get_matk2(src);
+ }else{
+ atkmin = battle_get_atk(src);
+ atkmax = battle_get_atk2(src);
+ }
+ if(mob_db[pd->class].range>3 )
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+
+ if(atkmin > atkmax) atkmin = atkmax;
+
+ cri = battle_get_critical(src);
+ cri -= battle_get_luk(target) * 2; // luk/5*10 => target_luk*2 not target_luk*3
+ if(battle_config.enemy_critical_rate != 100) {
+ cri = cri*battle_config.enemy_critical_rate/100;
+ if(cri < 1)
+ cri = 1;
+ }
+ if(t_sc_data != NULL && t_sc_data[SC_SLEEP].timer!=-1 )
+ cri <<=1;
+
+ if(skill_num == 0 && skill_lv >= 0 && battle_config.enemy_critical && (rand() % 1000) < cri)
+ {
+ damage += atkmax;
+ type = 0x0a;
+ }
+ else {
+ int vitbonusmax;
+
+ if(atkmax > atkmin)
+ damage += atkmin + rand() % (atkmax-atkmin + 1);
+ else
+ damage += atkmin ;
+ // スキル修正1(攻撃力倍化系)
+ // オーバートラスト(+5% 〜 +25%),他攻撃系スキルの場合ここで補正
+ // バッシュ,マグナムブレイク,
+ // ボーリングバッシュ,スピアブーメラン,ブランディッシュスピア,スピアスタッブ,
+ // メマーナイト,カートレボリューション
+ // ダブルストレイフィング,アローシャワー,チャージアロー,
+ // ソニックブロー
+ if(skill_num>0){
+ int i;
+ if( (i=skill_get_pl(skill_num))>0 )
+ s_ele=i;
+
+ flag=(flag&~BF_SKILLMASK)|BF_SKILL;
+ switch( skill_num ){
+ case SM_BASH: // バッシュ
+ damage = damage*(100+ 30*skill_lv)/100;
+ hitrate = (hitrate*(100+5*skill_lv))/100;
+ break;
+ case SM_MAGNUM: // マグナムブレイク
+ damage = damage*(5*skill_lv +(wflag)?65:115 )/100;
+ break;
+ case MC_MAMMONITE: // メマーナイト
+ damage = damage*(100+ 50*skill_lv)/100;
+ break;
+ case AC_DOUBLE: // ダブルストレイフィング
+ damage = damage*(180+ 20*skill_lv)/100;
+ div_=2;
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ break;
+ case AC_SHOWER: // アローシャワー
+ damage = damage*(75 + 5*skill_lv)/100;
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ break;
+ case AC_CHARGEARROW: // チャージアロー
+ damage = damage*150/100;
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ break;
+ case KN_PIERCE: // ピアース
+ damage = damage*(100+ 10*skill_lv)/100;
+ hitrate = hitrate*(100+5*skill_lv)/100;
+ div_=t_size+1;
+ damage*=div_;
+ break;
+ case KN_SPEARSTAB: // スピアスタブ
+ damage = damage*(100+ 15*skill_lv)/100;
+ break;
+ case KN_SPEARBOOMERANG: // スピアブーメラン
+ damage = damage*(100+ 50*skill_lv)/100;
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ break;
+ case KN_BRANDISHSPEAR: // ブランディッシュスピア
+ damage = damage*(100+ 20*skill_lv)/100;
+ if(skill_lv>3 && wflag==1) damage2+=damage/2;
+ if(skill_lv>6 && wflag==1) damage2+=damage/4;
+ if(skill_lv>9 && wflag==1) damage2+=damage/8;
+ if(skill_lv>6 && wflag==2) damage2+=damage/2;
+ if(skill_lv>9 && wflag==2) damage2+=damage/4;
+ if(skill_lv>9 && wflag==3) damage2+=damage/2;
+ damage +=damage2;
+ blewcount=0;
+ break;
+ case KN_BOWLINGBASH: // ボウリングバッシュ
+ damage = damage*(100+ 50*skill_lv)/100;
+ blewcount=0;
+ break;
+ case AS_SONICBLOW: // ソニックブロウ
+ damage = damage*(300+ 50*skill_lv)/100;
+ div_=8;
+ break;
+ case TF_SPRINKLESAND: // 砂まき
+ damage = damage*125/100;
+ break;
+ case MC_CARTREVOLUTION: // カートレボリューション
+ damage = (damage*150)/100;
+ break;
+ // 以下MOB
+ case NPC_COMBOATTACK: // 多段攻撃
+ div_=skill_get_num(skill_num,skill_lv);
+ damage *= div_;
+ break;
+ case NPC_RANDOMATTACK: // ランダムATK攻撃
+ damage = damage*(50+rand()%150)/100;
+ break;
+ // 属性攻撃(適当)
+ case NPC_WATERATTACK:
+ case NPC_GROUNDATTACK:
+ case NPC_FIREATTACK:
+ case NPC_WINDATTACK:
+ case NPC_POISONATTACK:
+ case NPC_HOLYATTACK:
+ case NPC_DARKNESSATTACK:
+ case NPC_TELEKINESISATTACK:
+ div_= pd->skillduration; // [Valaris]
+ break;
+ case NPC_GUIDEDATTACK:
+ hitrate = 1000000;
+ break;
+ case NPC_RANGEATTACK:
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ break;
+ case NPC_PIERCINGATT:
+ flag=(flag&~BF_RANGEMASK)|BF_SHORT;
+ break;
+ case RG_BACKSTAP: // バックスタブ
+ damage = damage*(300+ 40*skill_lv)/100;
+ hitrate = 1000000;
+ break;
+ case RG_RAID: // サプライズアタック
+ damage = damage*(100+ 40*skill_lv)/100;
+ break;
+ case RG_INTIMIDATE: // インティミデイト
+ damage = damage*(100+ 30*skill_lv)/100;
+ break;
+ case CR_SHIELDCHARGE: // シールドチャージ
+ damage = damage*(100+ 20*skill_lv)/100;
+ flag=(flag&~BF_RANGEMASK)|BF_SHORT;
+ s_ele = 0;
+ break;
+ case CR_SHIELDBOOMERANG: // シールドブーメラン
+ damage = damage*(100+ 30*skill_lv)/100;
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ s_ele = 0;
+ break;
+ case CR_HOLYCROSS: // ホーリークロス
+ damage = damage*(100+ 35*skill_lv)/100;
+ div_=2;
+ break;
+ case CR_GRANDCROSS:
+ hitrate= 1000000;
+ break;
+ case AM_DEMONSTRATION: // デモンストレーション
+ damage = damage*(100+ 20*skill_lv)/100;
+ damage2 = damage2*(100+ 20*skill_lv)/100;
+ break;
+ case AM_ACIDTERROR: // アシッドテラー
+ damage = damage*(100+ 40*skill_lv)/100;
+ damage2 = damage2*(100+ 40*skill_lv)/100;
+ break;
+ case MO_FINGEROFFENSIVE: //指弾
+ damage = damage * (100 + 50 * skill_lv) / 100;
+ div_ = 1;
+ break;
+ case MO_INVESTIGATE: // 発 勁
+ if(def1 < 1000000)
+ damage = damage*(100+ 75*skill_lv)/100 * (def1 + def2)/100;
+ hitrate = 1000000;
+ s_ele = 0;
+ break;
+ case MO_EXTREMITYFIST: // 阿修羅覇鳳拳
+ damage = damage * 8 + 250 + (skill_lv * 150);
+ hitrate = 1000000;
+ s_ele = 0;
+ break;
+ case MO_CHAINCOMBO: // 連打掌
+ damage = damage*(150+ 50*skill_lv)/100;
+ div_=4;
+ break;
+ case MO_COMBOFINISH: // 猛龍拳
+ damage = damage*(240+ 60*skill_lv)/100;
+ break;
+ case DC_THROWARROW: // 矢撃ち
+ damage = damage*(100+ 50 * skill_lv)/100;
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ break;
+ case BA_MUSICALSTRIKE: // ミュージカルストライク
+ damage = damage*(100+ 50 * skill_lv)/100;
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ break;
+ case CH_TIGERFIST: // 伏虎拳
+ damage = damage*(100+ 20*skill_lv)/100;
+ break;
+ case CH_CHAINCRUSH: // 連柱崩撃
+ damage = damage*(100+ 20*skill_lv)/100;
+ div_=skill_get_num(skill_num,skill_lv);
+ break;
+ case CH_PALMSTRIKE: // 猛虎硬派山
+ damage = damage*(50+ 100*skill_lv)/100;
+ break;
+ case LK_SPIRALPIERCE: /* スパイラルピアース */
+ damage = damage*(100+ 50*skill_lv)/100; //増加量が分からないので適当に
+ div_=5;
+ if(target->type == BL_PC)
+ ((struct map_session_data *)target)->canmove_tick = gettick() + 1000;
+ else if(target->type == BL_MOB)
+ ((struct mob_data *)target)->canmove_tick = gettick() + 1000;
+ break;
+ case LK_HEADCRUSH: /* ヘッドクラッシュ */
+ damage = damage*(100+ 20*skill_lv)/100;
+ break;
+ case LK_JOINTBEAT: /* ジョイントビート */
+ damage = damage*(50+ 10*skill_lv)/100;
+ break;
+ case ASC_METEORASSAULT: /* メテオアサルト */
+ damage = damage*(40+ 40*skill_lv)/100;
+ break;
+ case SN_SHARPSHOOTING: /* シャープシューティング */
+ damage += damage*(30*skill_lv)/100;
+ break;
+ case CG_ARROWVULCAN: /* アローバルカン */
+ damage = damage*(160+40*skill_lv)/100;
+ div_=9;
+ break;
+ case AS_SPLASHER: /* ベナムスプラッシャー */
+ damage = damage*(200+20*skill_lv)/100;
+ break;
+ }
+ }
+
+ if( skill_num!=NPC_CRITICALSLASH ){
+ // 対 象の防御力によるダメージの減少
+ // ディバインプロテクション(ここでいいのかな?)
+ if ( skill_num != MO_INVESTIGATE && skill_num != MO_EXTREMITYFIST && skill_num != KN_AUTOCOUNTER && def1 < 1000000 ) { //DEF, VIT無視
+ int t_def;
+ target_count = 1 + battle_counttargeted(target,src,battle_config.vit_penaly_count_lv);
+ if(battle_config.vit_penaly_type > 0) {
+ if(target_count >= battle_config.vit_penaly_count) {
+ if(battle_config.vit_penaly_type == 1) {
+ def1 = (def1 * (100 - (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num))/100;
+ def2 = (def2 * (100 - (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num))/100;
+ t_vit = (t_vit * (100 - (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num))/100;
+ }
+ else if(battle_config.vit_penaly_type == 2) {
+ def1 -= (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num;
+ def2 -= (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num;
+ t_vit -= (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num;
+ }
+ if(def1 < 0) def1 = 0;
+ if(def2 < 1) def2 = 1;
+ if(t_vit < 1) t_vit = 1;
+ }
+ }
+ t_def = def2*8/10;
+ vitbonusmax = (t_vit/20)*(t_vit/20)-1;
+ if(battle_config.pet_defense_type) {
+ damage = damage - (def1 * battle_config.pet_defense_type) - t_def - ((vitbonusmax < 1)?0: rand()%(vitbonusmax+1) );
+ }
+ else{
+ damage = damage * (100 - def1) /100 - t_def - ((vitbonusmax < 1)?0: rand()%(vitbonusmax+1) );
+ }
+ }
+ }
+ }
+
+ // 0未満だった場合1に補正
+ if(damage<1) damage=1;
+
+ // 回避修正
+ if(hitrate < 1000000)
+ hitrate = ( (hitrate>95)?95: ((hitrate<5)?5:hitrate) );
+ if( hitrate < 1000000 && // 必中攻撃
+ (t_sc_data != NULL && (t_sc_data[SC_SLEEP].timer!=-1 || // 睡眠は必中
+ t_sc_data[SC_STAN].timer!=-1 || // スタンは必中
+ t_sc_data[SC_FREEZE].timer!=-1 || (t_sc_data[SC_STONE].timer!=-1 && t_sc_data[SC_STONE].val2==0) ) ) ) // 凍結は必中
+ hitrate = 1000000;
+ if(type == 0 && rand()%100 >= hitrate) {
+ damage = damage2 = 0;
+ dmg_lv = ATK_FLEE;
+ } else {
+ dmg_lv = ATK_DEF;
+ }
+
+
+ if(t_sc_data) {
+ int cardfix=100;
+ if(t_sc_data[SC_DEFENDER].timer != -1 && flag&BF_LONG)
+ cardfix=cardfix*(100-t_sc_data[SC_DEFENDER].val2)/100;
+ if(cardfix != 100)
+ damage=damage*cardfix/100;
+ }
+ if(damage < 0) damage = 0;
+
+ // 属 性の適用
+ if(skill_num != 0 || s_ele != 0 || !battle_config.pet_attack_attr_none)
+ damage=battle_attr_fix(damage, s_ele, battle_get_element(target) );
+
+ if(skill_num==PA_PRESSURE) /* プレッシャー 必中? */
+ damage = 700+100*skill_lv;
+
+ // インベナム修正
+ if(skill_num==TF_POISON){
+ damage = battle_attr_fix(damage + 15*skill_lv, s_ele, battle_get_element(target) );
+ }
+ if(skill_num==MC_CARTREVOLUTION){
+ damage = battle_attr_fix(damage, 0, battle_get_element(target) );
+ }
+
+ // 完全回避の判定
+ if(battle_config.enemy_perfect_flee) {
+ if(skill_num == 0 && skill_lv >= 0 && tmd!=NULL && rand()%1000 < battle_get_flee2(target) ){
+ damage=0;
+ type=0x0b;
+ dmg_lv = ATK_LUCKY;
+ }
+ }
+
+// if(def1 >= 1000000 && damage > 0)
+ if(t_mode&0x40 && damage > 0)
+ damage = 1;
+
+ if(skill_num != CR_GRANDCROSS)
+ damage=battle_calc_damage(src,target,damage,div_,skill_num,skill_lv,flag);
+
+ wd.damage=damage;
+ wd.damage2=0;
+ wd.type=type;
+ wd.div_=div_;
+ wd.amotion=battle_get_amotion(src);
+ if(skill_num == KN_AUTOCOUNTER)
+ wd.amotion >>= 1;
+ wd.dmotion=battle_get_dmotion(target);
+ wd.blewcount=blewcount;
+ wd.flag=flag;
+ wd.dmg_lv=dmg_lv;
+
+ return wd;
+}
+
+static struct Damage battle_calc_mob_weapon_attack(
+ struct block_list *src,struct block_list *target,int skill_num,int skill_lv,int wflag)
+{
+ struct map_session_data *tsd=NULL;
+ struct mob_data* md=(struct mob_data *)src,*tmd=NULL;
+ int hitrate,flee,cri = 0,atkmin,atkmax;
+ int luk,target_count = 1;
+ int def1 = battle_get_def(target);
+ int def2 = battle_get_def2(target);
+ int t_vit = battle_get_vit(target);
+ struct Damage wd;
+ int damage,damage2=0,type,div_,blewcount=skill_get_blewcount(skill_num,skill_lv);
+ int flag,skill,ac_flag = 0,dmg_lv = 0;
+ int t_mode=0,t_race=0,t_size=1,s_race=0,s_ele=0;
+ struct status_change *sc_data,*t_sc_data;
+ short *sc_count;
+ short *option, *opt1, *opt2;
+
+ //return前の処理があるので情報出力部のみ変更
+ if( src == NULL || target == NULL || md == NULL ){
+ nullpo_info(NLP_MARK);
+ memset(&wd,0,sizeof(wd));
+ return wd;
+ }
+
+ s_race=battle_get_race(src);
+ s_ele=battle_get_attack_element(src);
+ sc_data=battle_get_sc_data(src);
+ sc_count=battle_get_sc_count(src);
+ option=battle_get_option(src);
+ opt1=battle_get_opt1(src);
+ opt2=battle_get_opt2(src);
+
+ // ターゲット
+ if(target->type==BL_PC)
+ tsd=(struct map_session_data *)target;
+ else if(target->type==BL_MOB)
+ tmd=(struct mob_data *)target;
+ t_race=battle_get_race( target );
+ t_size=battle_get_size( target );
+ t_mode=battle_get_mode( target );
+ t_sc_data=battle_get_sc_data( target );
+
+ if((skill_num == 0 || (target->type == BL_PC && battle_config.pc_auto_counter_type&2) ||
+ (target->type == BL_MOB && battle_config.monster_auto_counter_type&2)) && skill_lv >= 0) {
+ if(skill_num != CR_GRANDCROSS && t_sc_data && t_sc_data[SC_AUTOCOUNTER].timer != -1) {
+ int dir = map_calc_dir(src,target->x,target->y),t_dir = battle_get_dir(target);
+ int dist = distance(src->x,src->y,target->x,target->y);
+ if(dist <= 0 || map_check_dir(dir,t_dir) ) {
+ memset(&wd,0,sizeof(wd));
+ t_sc_data[SC_AUTOCOUNTER].val3 = 0;
+ t_sc_data[SC_AUTOCOUNTER].val4 = 1;
+ if(sc_data && sc_data[SC_AUTOCOUNTER].timer == -1) {
+ int range = battle_get_range(target);
+ if((target->type == BL_PC && ((struct map_session_data *)target)->status.weapon != 11 && dist <= range+1) ||
+ (target->type == BL_MOB && range <= 3 && dist <= range+1) )
+ t_sc_data[SC_AUTOCOUNTER].val3 = src->id;
+ }
+ return wd;
+ }
+ else ac_flag = 1;
+ }
+ }
+ flag=BF_SHORT|BF_WEAPON|BF_NORMAL; // 攻撃の種類の設定
+
+ // 回避率計算、回避判定は後で
+ flee = battle_get_flee(target);
+ if(battle_config.agi_penaly_type > 0 || battle_config.vit_penaly_type > 0)
+ target_count += battle_counttargeted(target,src,battle_config.agi_penaly_count_lv);
+ if(battle_config.agi_penaly_type > 0) {
+ if(target_count >= battle_config.agi_penaly_count) {
+ if(battle_config.agi_penaly_type == 1)
+ flee = (flee * (100 - (target_count - (battle_config.agi_penaly_count - 1))*battle_config.agi_penaly_num))/100;
+ else if(battle_config.agi_penaly_type == 2)
+ flee -= (target_count - (battle_config.agi_penaly_count - 1))*battle_config.agi_penaly_num;
+ if(flee < 1) flee = 1;
+ }
+ }
+ hitrate=battle_get_hit(src) - flee + 80;
+
+ type=0; // normal
+ div_ = 1; // single attack
+
+ luk=battle_get_luk(src);
+
+ if(battle_config.enemy_str)
+ damage = battle_get_baseatk(src);
+ else
+ damage = 0;
+ if(skill_num==HW_MAGICCRASHER){ /* マジッククラッシャーはMATKで殴る */
+ atkmin = battle_get_matk1(src);
+ atkmax = battle_get_matk2(src);
+ }else{
+ atkmin = battle_get_atk(src);
+ atkmax = battle_get_atk2(src);
+ }
+ if(mob_db[md->class].range>3 )
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+
+ if(atkmin > atkmax) atkmin = atkmax;
+
+ if(sc_data != NULL && sc_data[SC_MAXIMIZEPOWER].timer!=-1 ){ // マキシマイズパワー
+ atkmin=atkmax;
+ }
+
+ cri = battle_get_critical(src);
+ cri -= battle_get_luk(target) * 3;
+ if(battle_config.enemy_critical_rate != 100) {
+ cri = cri*battle_config.enemy_critical_rate/100;
+ if(cri < 1)
+ cri = 1;
+ }
+ if(t_sc_data != NULL && t_sc_data[SC_SLEEP].timer!=-1 ) // 睡眠中はクリティカルが倍に
+ cri <<=1;
+
+ if(ac_flag) cri = 1000;
+
+ if(skill_num == KN_AUTOCOUNTER) {
+ if(!(battle_config.monster_auto_counter_type&1))
+ cri = 1000;
+ else
+ cri <<= 1;
+ }
+
+ if(tsd && tsd->critical_def)
+ cri = cri * (100 - tsd->critical_def) / 100;
+
+ if((skill_num == 0 || skill_num == KN_AUTOCOUNTER) && skill_lv >= 0 && battle_config.enemy_critical && (rand() % 1000) < cri) // 判定(スキルの場合は無視)
+ // 敵の判定
+ {
+ damage += atkmax;
+ type = 0x0a;
+ }
+ else {
+ int vitbonusmax;
+
+ if(atkmax > atkmin)
+ damage += atkmin + rand() % (atkmax-atkmin + 1);
+ else
+ damage += atkmin ;
+ // スキル修正1(攻撃力倍化系)
+ // オーバートラスト(+5% 〜 +25%),他攻撃系スキルの場合ここで補正
+ // バッシュ,マグナムブレイク,
+ // ボーリングバッシュ,スピアブーメラン,ブランディッシュスピア,スピアスタッブ,
+ // メマーナイト,カートレボリューション
+ // ダブルストレイフィング,アローシャワー,チャージアロー,
+ // ソニックブロー
+ if(sc_data){ //状態異常中のダメージ追加
+ if(sc_data[SC_OVERTHRUST].timer!=-1) // オーバートラスト
+ damage += damage*(5*sc_data[SC_OVERTHRUST].val1)/100;
+ if(sc_data[SC_TRUESIGHT].timer!=-1) // トゥルーサイト
+ damage += damage*(2*sc_data[SC_TRUESIGHT].val1)/100;
+ if(sc_data[SC_BERSERK].timer!=-1) // バーサーク
+ damage += damage*50/100;
+ }
+
+ if(skill_num>0){
+ int i;
+ if( (i=skill_get_pl(skill_num))>0 )
+ s_ele=i;
+
+ flag=(flag&~BF_SKILLMASK)|BF_SKILL;
+ switch( skill_num ){
+ case SM_BASH: // バッシュ
+ damage = damage*(100+ 30*skill_lv)/100;
+ hitrate = (hitrate*(100+5*skill_lv))/100;
+ break;
+ case SM_MAGNUM: // マグナムブレイク
+ damage = damage*(5*skill_lv +(wflag)?65:115 )/100;
+ break;
+ case MC_MAMMONITE: // メマーナイト
+ damage = damage*(100+ 50*skill_lv)/100;
+ break;
+ case AC_DOUBLE: // ダブルストレイフィング
+ damage = damage*(180+ 20*skill_lv)/100;
+ div_=2;
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ break;
+ case AC_SHOWER: // アローシャワー
+ damage = damage*(75 + 5*skill_lv)/100;
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ break;
+ case AC_CHARGEARROW: // チャージアロー
+ damage = damage*150/100;
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ break;
+ case KN_PIERCE: // ピアース
+ damage = damage*(100+ 10*skill_lv)/100;
+ hitrate=hitrate*(100+5*skill_lv)/100;
+ div_=t_size+1;
+ damage*=div_;
+ break;
+ case KN_SPEARSTAB: // スピアスタブ
+ damage = damage*(100+ 15*skill_lv)/100;
+ break;
+ case KN_SPEARBOOMERANG: // スピアブーメラン
+ damage = damage*(100+ 50*skill_lv)/100;
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ break;
+ case KN_BRANDISHSPEAR: // ブランディッシュスピア
+ damage = damage*(100+ 20*skill_lv)/100;
+ if(skill_lv>3 && wflag==1) damage2+=damage/2;
+ if(skill_lv>6 && wflag==1) damage2+=damage/4;
+ if(skill_lv>9 && wflag==1) damage2+=damage/8;
+ if(skill_lv>6 && wflag==2) damage2+=damage/2;
+ if(skill_lv>9 && wflag==2) damage2+=damage/4;
+ if(skill_lv>9 && wflag==3) damage2+=damage/2;
+ damage +=damage2;
+ blewcount=0;
+ break;
+ case KN_BOWLINGBASH: // ボウリングバッシュ
+ damage = damage*(100+ 50*skill_lv)/100;
+ blewcount=0;
+ break;
+ case KN_AUTOCOUNTER:
+ if(battle_config.monster_auto_counter_type&1)
+ hitrate += 20;
+ else
+ hitrate = 1000000;
+ flag=(flag&~BF_SKILLMASK)|BF_NORMAL;
+ break;
+ case AS_SONICBLOW: // ソニックブロウ
+ damage = damage*(300+ 50*skill_lv)/100;
+ div_=8;
+ break;
+ case TF_SPRINKLESAND: // 砂まき
+ damage = damage*125/100;
+ break;
+ case MC_CARTREVOLUTION: // カートレボリューション
+ damage = (damage*150)/100;
+ break;
+ // 以下MOB
+ case NPC_COMBOATTACK: // 多段攻撃
+ div_=skill_get_num(skill_num,skill_lv);
+ damage *= div_;
+ break;
+ case NPC_RANDOMATTACK: // ランダムATK攻撃
+ damage = damage*(50+rand()%150)/100;
+ break;
+ // 属性攻撃(適当)
+ case NPC_WATERATTACK:
+ case NPC_GROUNDATTACK:
+ case NPC_FIREATTACK:
+ case NPC_WINDATTACK:
+ case NPC_POISONATTACK:
+ case NPC_HOLYATTACK:
+ case NPC_DARKNESSATTACK:
+ case NPC_TELEKINESISATTACK:
+ damage = damage*(100+25*(skill_lv-1))/100;
+ break;
+ case NPC_GUIDEDATTACK:
+ hitrate = 1000000;
+ break;
+ case NPC_RANGEATTACK:
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ break;
+ case NPC_PIERCINGATT:
+ flag=(flag&~BF_RANGEMASK)|BF_SHORT;
+ break;
+ case RG_BACKSTAP: // バックスタブ
+ damage = damage*(300+ 40*skill_lv)/100;
+ hitrate = 1000000;
+ break;
+ case RG_RAID: // サプライズアタック
+ damage = damage*(100+ 40*skill_lv)/100;
+ break;
+ case RG_INTIMIDATE: // インティミデイト
+ damage = damage*(100+ 30*skill_lv)/100;
+ break;
+ case CR_SHIELDCHARGE: // シールドチャージ
+ damage = damage*(100+ 20*skill_lv)/100;
+ flag=(flag&~BF_RANGEMASK)|BF_SHORT;
+ s_ele = 0;
+ break;
+ case CR_SHIELDBOOMERANG: // シールドブーメラン
+ damage = damage*(100+ 30*skill_lv)/100;
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ s_ele = 0;
+ break;
+ case CR_HOLYCROSS: // ホーリークロス
+ damage = damage*(100+ 35*skill_lv)/100;
+ div_=2;
+ break;
+ case CR_GRANDCROSS:
+ hitrate= 1000000;
+ break;
+ case AM_DEMONSTRATION: // デモンストレーション
+ damage = damage*(100+ 20*skill_lv)/100;
+ damage2 = damage2*(100+ 20*skill_lv)/100;
+ break;
+ case AM_ACIDTERROR: // アシッドテラー
+ damage = damage*(100+ 40*skill_lv)/100;
+ damage2 = damage2*(100+ 40*skill_lv)/100;
+ break;
+ case MO_FINGEROFFENSIVE: //指弾
+ damage = damage * (100 + 50 * skill_lv) / 100;
+ div_ = 1;
+ break;
+ case MO_INVESTIGATE: // 発 勁
+ if(def1 < 1000000)
+ damage = damage*(100+ 75*skill_lv)/100 * (def1 + def2)/100;
+ hitrate = 1000000;
+ s_ele = 0;
+ break;
+ case MO_EXTREMITYFIST: // 阿修羅覇鳳拳
+ damage = damage * 8 + 250 + (skill_lv * 150);
+ hitrate = 1000000;
+ s_ele = 0;
+ break;
+ case MO_CHAINCOMBO: // 連打掌
+ damage = damage*(150+ 50*skill_lv)/100;
+ div_=4;
+ break;
+ case BA_MUSICALSTRIKE: // ミュージカルストライク
+ damage = damage*(100+ 50 * skill_lv)/100;
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ break;
+ case DC_THROWARROW: // 矢撃ち
+ damage = damage*(100+ 50 * skill_lv)/100;
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ break;
+ case MO_COMBOFINISH: // 猛龍拳
+ damage = damage*(240+ 60*skill_lv)/100;
+ break;
+ case CH_TIGERFIST: // 伏虎拳
+ damage = damage*(100+ 20*skill_lv)/100;
+ break;
+ case CH_CHAINCRUSH: // 連柱崩撃
+ damage = damage*(100+ 20*skill_lv)/100;
+ div_=skill_get_num(skill_num,skill_lv);
+ break;
+ case CH_PALMSTRIKE: // 猛虎硬派山
+ damage = damage*(50+ 100*skill_lv)/100;
+ break;
+ case LK_SPIRALPIERCE: /* スパイラルピアース */
+ damage = damage*(100+ 50*skill_lv)/100; //増加量が分からないので適当に
+ div_=5;
+ if(tsd)
+ tsd->canmove_tick = gettick() + 1000;
+ else if(tmd)
+ tmd->canmove_tick = gettick() + 1000;
+ break;
+ case LK_HEADCRUSH: /* ヘッドクラッシュ */
+ damage = damage*(100+ 20*skill_lv)/100;
+ break;
+ case LK_JOINTBEAT: /* ジョイントビート */
+ damage = damage*(50+ 10*skill_lv)/100;
+ break;
+ case ASC_METEORASSAULT: /* メテオアサルト */
+ damage = damage*(40+ 40*skill_lv)/100;
+ break;
+ case SN_SHARPSHOOTING: /* シャープシューティング */
+ damage += damage*(30*skill_lv)/100;
+ break;
+ case CG_ARROWVULCAN: /* アローバルカン */
+ damage = damage*(160+40*skill_lv)/100;
+ div_=9;
+ break;
+ case AS_SPLASHER: /* ベナムスプラッシャー */
+ damage = damage*(200+20*skill_lv)/100;
+ break;
+ }
+ }
+
+ if( skill_num!=NPC_CRITICALSLASH ){
+ // 対 象の防御力によるダメージの減少
+ // ディバインプロテクション(ここでいいのかな?)
+ if ( skill_num != MO_INVESTIGATE && skill_num != MO_EXTREMITYFIST && skill_num != KN_AUTOCOUNTER && def1 < 1000000) { //DEF, VIT無視
+ int t_def;
+ target_count = 1 + battle_counttargeted(target,src,battle_config.vit_penaly_count_lv);
+ if(battle_config.vit_penaly_type > 0) {
+ if(target_count >= battle_config.vit_penaly_count) {
+ if(battle_config.vit_penaly_type == 1) {
+ def1 = (def1 * (100 - (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num))/100;
+ def2 = (def2 * (100 - (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num))/100;
+ t_vit = (t_vit * (100 - (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num))/100;
+ }
+ else if(battle_config.vit_penaly_type == 2) {
+ def1 -= (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num;
+ def2 -= (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num;
+ t_vit -= (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num;
+ }
+ if(def1 < 0) def1 = 0;
+ if(def2 < 1) def2 = 1;
+ if(t_vit < 1) t_vit = 1;
+ }
+ }
+ t_def = def2*8/10;
+ if(battle_check_undead(s_race,battle_get_elem_type(src)) || s_race==6)
+ if(tsd && (skill=pc_checkskill(tsd,AL_DP)) > 0 )
+ t_def += skill*3;
+
+ vitbonusmax = (t_vit/20)*(t_vit/20)-1;
+ if(battle_config.monster_defense_type) {
+ damage = damage - (def1 * battle_config.monster_defense_type) - t_def - ((vitbonusmax < 1)?0: rand()%(vitbonusmax+1) );
+ }
+ else{
+ damage = damage * (100 - def1) /100 - t_def - ((vitbonusmax < 1)?0: rand()%(vitbonusmax+1) );
+ }
+ }
+ }
+ }
+
+ // 0未満だった場合1に補正
+ if(damage<1) damage=1;
+
+ // 回避修正
+ if(hitrate < 1000000)
+ hitrate = ( (hitrate>95)?95: ((hitrate<5)?5:hitrate) );
+ if( hitrate < 1000000 && // 必中攻撃
+ (t_sc_data != NULL && (t_sc_data[SC_SLEEP].timer!=-1 || // 睡眠は必中
+ t_sc_data[SC_STAN].timer!=-1 || // スタンは必中
+ t_sc_data[SC_FREEZE].timer!=-1 || (t_sc_data[SC_STONE].timer!=-1 && t_sc_data[SC_STONE].val2==0) ) ) ) // 凍結は必中
+ hitrate = 1000000;
+ if(type == 0 && rand()%100 >= hitrate) {
+ damage = damage2 = 0;
+ dmg_lv = ATK_FLEE;
+ } else {
+ dmg_lv = ATK_DEF;
+ }
+
+ if(tsd){
+ int cardfix=100,i;
+ cardfix=cardfix*(100-tsd->subele[s_ele])/100; // 属 性によるダメージ耐性
+ cardfix=cardfix*(100-tsd->subrace[s_race])/100; // 種族によるダメージ耐性
+ if(mob_db[md->class].mode & 0x20)
+ cardfix=cardfix*(100-tsd->subrace[10])/100;
+ else
+ cardfix=cardfix*(100-tsd->subrace[11])/100;
+ for(i=0;i<tsd->add_def_class_count;i++) {
+ if(tsd->add_def_classid[i] == md->class) {
+ cardfix=cardfix*(100-tsd->add_def_classrate[i])/100;
+ break;
+ }
+ }
+ if(flag&BF_LONG)
+ cardfix=cardfix*(100-tsd->long_attack_def_rate)/100;
+ if(flag&BF_SHORT)
+ cardfix=cardfix*(100-tsd->near_attack_def_rate)/100;
+ damage=damage*cardfix/100;
+ }
+ if(t_sc_data) {
+ int cardfix=100;
+ if(t_sc_data[SC_DEFENDER].timer != -1 && flag&BF_LONG)
+ cardfix=cardfix*(100-t_sc_data[SC_DEFENDER].val2)/100;
+ if(cardfix != 100)
+ damage=damage*cardfix/100;
+ }
+ if(t_sc_data && t_sc_data[SC_ASSUMPTIO].timer != -1){ //アシャンプティオ
+ if(!map[target->m].flag.pvp)
+ damage=damage/3;
+ else
+ damage=damage/2;
+ }
+
+ if(damage < 0) damage = 0;
+
+ // 属 性の適用
+ if (!((battle_config.mob_ghostring_fix == 1) &&
+ (battle_get_element(target) == 8) &&
+ (target->type==BL_PC))) // [MouseJstr]
+ if(skill_num != 0 || s_ele != 0 || !battle_config.mob_attack_attr_none)
+ damage=battle_attr_fix(damage, s_ele, battle_get_element(target) );
+
+ if(sc_data && sc_data[SC_AURABLADE].timer!=-1) /* オーラブレード 必中 */
+ damage += sc_data[SC_AURABLADE].val1 * 10;
+ if(skill_num==PA_PRESSURE) /* プレッシャー 必中? */
+ damage = 700+100*skill_lv;
+
+ // インベナム修正
+ if(skill_num==TF_POISON){
+ damage = battle_attr_fix(damage + 15*skill_lv, s_ele, battle_get_element(target) );
+ }
+ if(skill_num==MC_CARTREVOLUTION){
+ damage = battle_attr_fix(damage, 0, battle_get_element(target) );
+ }
+
+ // 完全回避の判定
+ if(skill_num == 0 && skill_lv >= 0 && tsd!=NULL && rand()%1000 < battle_get_flee2(target) ){
+ damage=0;
+ type=0x0b;
+ dmg_lv = ATK_LUCKY;
+ }
+
+ if(battle_config.enemy_perfect_flee) {
+ if(skill_num == 0 && skill_lv >= 0 && tmd!=NULL && rand()%1000 < battle_get_flee2(target) ){
+ damage=0;
+ type=0x0b;
+ dmg_lv = ATK_LUCKY;
+ }
+ }
+
+// if(def1 >= 1000000 && damage > 0)
+ if(t_mode&0x40 && damage > 0)
+ damage = 1;
+
+ if( tsd && tsd->special_state.no_weapon_damage)
+ damage = 0;
+
+ if(skill_num != CR_GRANDCROSS)
+ damage=battle_calc_damage(src,target,damage,div_,skill_num,skill_lv,flag);
+
+ wd.damage=damage;
+ wd.damage2=0;
+ wd.type=type;
+ wd.div_=div_;
+ wd.amotion=battle_get_amotion(src);
+ if(skill_num == KN_AUTOCOUNTER)
+ wd.amotion >>= 1;
+ wd.dmotion=battle_get_dmotion(target);
+ wd.blewcount=blewcount;
+ wd.flag=flag;
+ wd.dmg_lv=dmg_lv;
+ return wd;
+}
+/*
+ * =========================================================================
+ * PCの武器による攻撃
+ *-------------------------------------------------------------------------
+ */
+static struct Damage battle_calc_pc_weapon_attack(
+ struct block_list *src,struct block_list *target,int skill_num,int skill_lv,int wflag)
+{
+ struct map_session_data *sd=(struct map_session_data *)src,*tsd=NULL;
+ struct mob_data *tmd=NULL;
+ int hitrate,flee,cri = 0,atkmin,atkmax;
+ int dex,luk,target_count = 1;
+ int def1 = battle_get_def(target);
+ int def2 = battle_get_def2(target);
+ int t_vit = battle_get_vit(target);
+ struct Damage wd;
+ int damage,damage2,damage3=0,damage4=0,type,div_,blewcount=skill_get_blewcount(skill_num,skill_lv);
+ int flag,skill,dmg_lv = 0;
+ int t_mode=0,t_race=0,t_size=1,s_race=7,s_ele=0;
+ struct status_change *sc_data,*t_sc_data;
+ short *sc_count;
+ short *option, *opt1, *opt2;
+ int atkmax_=0, atkmin_=0, s_ele_; //二刀流用
+ int watk,watk_,cardfix,t_ele;
+ int da=0,i,t_class,ac_flag = 0;
+ int idef_flag=0,idef_flag_=0;
+
+ //return前の処理があるので情報出力部のみ変更
+ if( src == NULL || target == NULL || sd == NULL ){
+ nullpo_info(NLP_MARK);
+ memset(&wd,0,sizeof(wd));
+ return wd;
+ }
+
+
+ // アタッカー
+ s_race=battle_get_race(src); //種族
+ s_ele=battle_get_attack_element(src); //属性
+ s_ele_=battle_get_attack_element2(src); //左手属性
+ sc_data=battle_get_sc_data(src); //ステータス異常
+ sc_count=battle_get_sc_count(src); //ステータス異常の数
+ option=battle_get_option(src); //鷹とかペコとかカートとか
+ opt1=battle_get_opt1(src); //石化、凍結、スタン、睡眠、暗闇
+ opt2=battle_get_opt2(src); //毒、呪い、沈黙、暗闇?
+
+ if(skill_num != CR_GRANDCROSS) //グランドクロスでないなら
+ sd->state.attack_type = BF_WEAPON; //攻撃タイプは武器攻撃
+
+ // ターゲット
+ if(target->type==BL_PC) //対象がPCなら
+ tsd=(struct map_session_data *)target; //tsdに代入(tmdはNULL)
+ else if(target->type==BL_MOB) //対象がMobなら
+ tmd=(struct mob_data *)target; //tmdに代入(tsdはNULL)
+ t_race=battle_get_race( target ); //対象の種族
+ t_ele=battle_get_elem_type(target); //対象の属性
+ t_size=battle_get_size( target ); //対象のサイズ
+ t_mode=battle_get_mode( target ); //対象のMode
+ t_sc_data=battle_get_sc_data( target ); //対象のステータス異常
+
+//オートカウンター処理ここから
+ if((skill_num == 0 || (target->type == BL_PC && battle_config.pc_auto_counter_type&2) ||
+ (target->type == BL_MOB && battle_config.monster_auto_counter_type&2)) && skill_lv >= 0) {
+ if(skill_num != CR_GRANDCROSS && t_sc_data && t_sc_data[SC_AUTOCOUNTER].timer != -1) { //グランドクロスでなく、対象がオートカウンター状態の場合
+ int dir = map_calc_dir(src,target->x,target->y),t_dir = battle_get_dir(target);
+ int dist = distance(src->x,src->y,target->x,target->y);
+ if(dist <= 0 || map_check_dir(dir,t_dir) ) { //対象との距離が0以下、または対象の正面?
+ memset(&wd,0,sizeof(wd));
+ t_sc_data[SC_AUTOCOUNTER].val3 = 0;
+ t_sc_data[SC_AUTOCOUNTER].val4 = 1;
+ if(sc_data && sc_data[SC_AUTOCOUNTER].timer == -1) { //自分がオートカウンター状態
+ int range = battle_get_range(target);
+ if((target->type == BL_PC && ((struct map_session_data *)target)->status.weapon != 11 && dist <= range+1) || //対象がPCで武器が弓矢でなく射程内
+ (target->type == BL_MOB && range <= 3 && dist <= range+1) ) //または対象がMobで射程が3以下で射程内
+ t_sc_data[SC_AUTOCOUNTER].val3 = src->id;
+ }
+ return wd; //ダメージ構造体を返して終了
+ }
+ else ac_flag = 1;
+ }
+ }
+//オートカウンター処理ここまで
+
+ flag=BF_SHORT|BF_WEAPON|BF_NORMAL; // 攻撃の種類の設定
+
+ // 回避率計算、回避判定は後で
+ flee = battle_get_flee(target);
+ if(battle_config.agi_penaly_type > 0 || battle_config.vit_penaly_type > 0) //AGI、VITペナルティ設定が有効
+ target_count += battle_counttargeted(target,src,battle_config.agi_penaly_count_lv); //対象の数を算出
+ if(battle_config.agi_penaly_type > 0) {
+ if(target_count >= battle_config.agi_penaly_count) { //ペナルティ設定より対象が多い
+ if(battle_config.agi_penaly_type == 1) //回避率がagi_penaly_num%ずつ減少
+ flee = (flee * (100 - (target_count - (battle_config.agi_penaly_count - 1))*battle_config.agi_penaly_num))/100;
+ else if(battle_config.agi_penaly_type == 2) //回避率がagi_penaly_num分減少
+ flee -= (target_count - (battle_config.agi_penaly_count - 1))*battle_config.agi_penaly_num;
+ if(flee < 1) flee = 1; //回避率は最低でも1
+ }
+ }
+ hitrate=battle_get_hit(src) - flee + 80; //命中率計算
+
+ type=0; // normal
+ div_ = 1; // single attack
+
+ dex=battle_get_dex(src); //DEX
+ luk=battle_get_luk(src); //LUK
+ watk = battle_get_atk(src); //ATK
+ watk_ = battle_get_atk_(src); //ATK左手
+
+ if(skill_num==HW_MAGICCRASHER){ /* マジッククラッシャーはMATKで殴る */
+ damage = damage2 = battle_get_matk1(src); //damega,damega2初登場、base_atkの取得
+ }else{
+ damage = damage2 = battle_get_baseatk(&sd->bl); //damega,damega2初登場、base_atkの取得
+ }
+ atkmin = atkmin_ = dex; //最低ATKはDEXで初期化?
+ sd->state.arrow_atk = 0; //arrow_atk初期化
+ if(sd->equip_index[9] >= 0 && sd->inventory_data[sd->equip_index[9]])
+ atkmin = atkmin*(80 + sd->inventory_data[sd->equip_index[9]]->wlv*20)/100;
+ if(sd->equip_index[8] >= 0 && sd->inventory_data[sd->equip_index[8]])
+ atkmin_ = atkmin_*(80 + sd->inventory_data[sd->equip_index[8]]->wlv*20)/100;
+ if(sd->status.weapon == 11) { //武器が弓矢の場合
+ atkmin = watk * ((atkmin<watk)? atkmin:watk)/100; //弓用最低ATK計算
+ flag=(flag&~BF_RANGEMASK)|BF_LONG; //遠距離攻撃フラグを有効
+ if(sd->arrow_ele > 0) //属性矢なら属性を矢の属性に変更
+ s_ele = sd->arrow_ele;
+ sd->state.arrow_atk = 1; //arrow_atk有効化
+ }
+
+ // サイズ修正
+ // ペコ騎乗していて、槍で攻撃した場合は中型のサイズ修正を100にする
+ // ウェポンパーフェクション,ドレイクC
+ if(((sd->special_state.no_sizefix) || (pc_isriding(sd) && (sd->status.weapon==4 || sd->status.weapon==5) && t_size==1) || skill_num == MO_EXTREMITYFIST)){ //ペコ騎乗していて、槍で中型を攻撃
+ atkmax = watk;
+ atkmax_ = watk_;
+ } else {
+ atkmax = (watk * sd->atkmods[ t_size ]) / 100;
+ atkmin = (atkmin * sd->atkmods[ t_size ]) / 100;
+ atkmax_ = (watk_ * sd->atkmods_[ t_size ]) / 100;
+ atkmin_ = (atkmin_ * sd->atkmods[ t_size ]) / 100;
+ }
+ if( (sc_data != NULL && sc_data[SC_WEAPONPERFECTION].timer!=-1) || (sd->special_state.no_sizefix)) { // ウェポンパーフェクション || ドレイクカード
+ atkmax = watk;
+ atkmax_ = watk_;
+ }
+
+ if(atkmin > atkmax && !(sd->state.arrow_atk)) atkmin = atkmax; //弓は最低が上回る場合あり
+ if(atkmin_ > atkmax_) atkmin_ = atkmax_;
+
+ if(sc_data != NULL && sc_data[SC_MAXIMIZEPOWER].timer!=-1 ){ // マキシマイズパワー
+ atkmin=atkmax;
+ atkmin_=atkmax_;
+ }
+
+ //ダブルアタック判定
+ if(sd->weapontype1 == 0x01) {
+ if(skill_num == 0 && skill_lv >= 0 && (skill = pc_checkskill(sd,TF_DOUBLE)) > 0)
+ da = (rand()%100 < (skill*5)) ? 1:0;
+ }
+
+ //三段掌
+ if(skill_num == 0 && skill_lv >= 0 && (skill = pc_checkskill(sd,MO_TRIPLEATTACK)) > 0 && sd->status.weapon <= 16 && !sd->state.arrow_atk) {
+ da = (rand()%100 < (30 - skill)) ? 2:0;
+ }
+
+ if(sd->double_rate > 0 && da == 0 && skill_num == 0 && skill_lv >= 0)
+ da = (rand()%100 < sd->double_rate) ? 1:0;
+
+ // 過剰精錬ボーナス
+ if(sd->overrefine>0 )
+ damage+=(rand()%sd->overrefine)+1;
+ if(sd->overrefine_>0 )
+ damage2+=(rand()%sd->overrefine_)+1;
+
+ if(da == 0){ //ダブルアタックが発動していない
+ // クリティカル計算
+ cri = battle_get_critical(src);
+
+ if(sd->state.arrow_atk)
+ cri += sd->arrow_cri;
+ if(sd->status.weapon == 16)
+ // カタールの場合、クリティカルを倍に
+ cri <<=1;
+ cri -= battle_get_luk(target) * 3;
+ if(t_sc_data != NULL && t_sc_data[SC_SLEEP].timer!=-1 ) // 睡眠中はクリティカルが倍に
+ cri <<=1;
+ if(ac_flag) cri = 1000;
+
+ if(skill_num == KN_AUTOCOUNTER) {
+ if(!(battle_config.pc_auto_counter_type&1))
+ cri = 1000;
+ else
+ cri <<= 1;
+ }
+
+ if(skill_num == SN_SHARPSHOOTING && rand()%100 < 50)
+ cri = 1000;
+ }
+
+ if(tsd && tsd->critical_def)
+ cri = cri * (100-tsd->critical_def) / 100;
+
+ if(da == 0 && (skill_num==0 || skill_num == KN_AUTOCOUNTER || skill_num == SN_SHARPSHOOTING) && skill_lv >= 0 && //ダブルアタックが発動していない
+ (rand() % 1000) < cri) // 判定(スキルの場合は無視)
+ {
+ damage += atkmax;
+ damage2 += atkmax_;
+ if(sd->atk_rate != 100) {
+ damage = (damage * sd->atk_rate)/100;
+ damage2 = (damage2 * sd->atk_rate)/100;
+ }
+ if(sd->state.arrow_atk)
+ damage += sd->arrow_atk;
+ type = 0x0a;
+
+/* if(def1 < 1000000) {
+ if(sd->def_ratio_atk_ele & (1<<t_ele) || sd->def_ratio_atk_race & (1<<t_race)) {
+ damage = (damage * (def1 + def2))/100;
+ idef_flag = 1;
+ }
+ if(sd->def_ratio_atk_ele_ & (1<<t_ele) || sd->def_ratio_atk_race_ & (1<<t_race)) {
+ damage2 = (damage2 * (def1 + def2))/100;
+ idef_flag_ = 1;
+ }
+ if(t_mode & 0x20) {
+ if(!idef_flag && sd->def_ratio_atk_race & (1<<10)) {
+ damage = (damage * (def1 + def2))/100;
+ idef_flag = 1;
+ }
+ if(!idef_flag_ && sd->def_ratio_atk_race_ & (1<<10)) {
+ damage2 = (damage2 * (def1 + def2))/100;
+ idef_flag_ = 1;
+ }
+ }
+ else {
+ if(!idef_flag && sd->def_ratio_atk_race & (1<<11)) {
+ damage = (damage * (def1 + def2))/100;
+ idef_flag = 1;
+ }
+ if(!idef_flag_ && sd->def_ratio_atk_race_ & (1<<11)) {
+ damage2 = (damage2 * (def1 + def2))/100;
+ idef_flag_ = 1;
+ }
+ }
+ }*/
+ }
+ else {
+ int vitbonusmax;
+
+ if(atkmax > atkmin)
+ damage += atkmin + rand() % (atkmax-atkmin + 1);
+ else
+ damage += atkmin ;
+ if(atkmax_ > atkmin_)
+ damage2 += atkmin_ + rand() % (atkmax_-atkmin_ + 1);
+ else
+ damage2 += atkmin_ ;
+ if(sd->atk_rate != 100) {
+ damage = (damage * sd->atk_rate)/100;
+ damage2 = (damage2 * sd->atk_rate)/100;
+ }
+
+ if(sd->state.arrow_atk) {
+ if(sd->arrow_atk > 0)
+ damage += rand()%(sd->arrow_atk+1);
+ hitrate += sd->arrow_hit;
+ }
+
+ if(skill_num != MO_INVESTIGATE && def1 < 1000000) {
+ if(sd->def_ratio_atk_ele & (1<<t_ele) || sd->def_ratio_atk_race & (1<<t_race)) {
+ damage = (damage * (def1 + def2))/100;
+ idef_flag = 1;
+ }
+ if(sd->def_ratio_atk_ele_ & (1<<t_ele) || sd->def_ratio_atk_race_ & (1<<t_race)) {
+ damage2 = (damage2 * (def1 + def2))/100;
+ idef_flag_ = 1;
+ }
+ if(t_mode & 0x20) {
+ if(!idef_flag && sd->def_ratio_atk_race & (1<<10)) {
+ damage = (damage * (def1 + def2))/100;
+ idef_flag = 1;
+ }
+ if(!idef_flag_ && sd->def_ratio_atk_race_ & (1<<10)) {
+ damage2 = (damage2 * (def1 + def2))/100;
+ idef_flag_ = 1;
+ }
+ }
+ else {
+ if(!idef_flag && sd->def_ratio_atk_race & (1<<11)) {
+ damage = (damage * (def1 + def2))/100;
+ idef_flag = 1;
+ }
+ if(!idef_flag_ && sd->def_ratio_atk_race_ & (1<<11)) {
+ damage2 = (damage2 * (def1 + def2))/100;
+ idef_flag_ = 1;
+ }
+ }
+ }
+
+ // スキル修正1(攻撃力倍化系)
+ // オーバートラスト(+5% 〜 +25%),他攻撃系スキルの場合ここで補正
+ // バッシュ,マグナムブレイク,
+ // ボーリングバッシュ,スピアブーメラン,ブランディッシュスピア,スピアスタッブ,
+ // メマーナイト,カートレボリューション
+ // ダブルストレイフィング,アローシャワー,チャージアロー,
+ // ソニックブロー
+ if(sc_data){ //状態異常中のダメージ追加
+ if(sc_data[SC_OVERTHRUST].timer!=-1){ // オーバートラスト
+ damage += damage*(5*sc_data[SC_OVERTHRUST].val1)/100;
+ damage2 += damage2*(5*sc_data[SC_OVERTHRUST].val1)/100;
+ }
+ if(sc_data[SC_TRUESIGHT].timer!=-1){ // トゥルーサイト
+ damage += damage*(2*sc_data[SC_TRUESIGHT].val1)/100;
+ damage2 += damage2*(2*sc_data[SC_TRUESIGHT].val1)/100;
+ }
+ if(sc_data[SC_BERSERK].timer!=-1){ // バーサーク
+ damage += damage*50/100;
+ damage2 += damage2*50/100;
+ }
+ }
+
+ if(skill_num>0){
+ int i;
+ if( (i=skill_get_pl(skill_num))>0 )
+ s_ele=s_ele_=i;
+
+ flag=(flag&~BF_SKILLMASK)|BF_SKILL;
+ switch( skill_num ){
+ case SM_BASH: // バッシュ
+ damage = damage*(100+ 30*skill_lv)/100;
+ damage2 = damage2*(100+ 30*skill_lv)/100;
+ hitrate = (hitrate*(100+5*skill_lv))/100;
+ break;
+ case SM_MAGNUM: // マグナムブレイク
+ damage = damage*(5*skill_lv +(wflag)?65:115 )/100;
+ damage2 = damage2*(5*skill_lv +(wflag)?65:115 )/100;
+ break;
+ case MC_MAMMONITE: // メマーナイト
+ damage = damage*(100+ 50*skill_lv)/100;
+ damage2 = damage2*(100+ 50*skill_lv)/100;
+ break;
+ case AC_DOUBLE: // ダブルストレイフィング
+ if(!sd->state.arrow_atk && sd->arrow_atk > 0) {
+ int arr = rand()%(sd->arrow_atk+1);
+ damage += arr;
+ damage2 += arr;
+ }
+ damage = damage*(180+ 20*skill_lv)/100;
+ damage2 = damage2*(180+ 20*skill_lv)/100;
+ div_=2;
+ if(sd->arrow_ele > 0) {
+ s_ele = sd->arrow_ele;
+ s_ele_ = sd->arrow_ele;
+ }
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ sd->state.arrow_atk = 1;
+ break;
+ case AC_SHOWER: // アローシャワー
+ if(!sd->state.arrow_atk && sd->arrow_atk > 0) {
+ int arr = rand()%(sd->arrow_atk+1);
+ damage += arr;
+ damage2 += arr;
+ }
+ damage = damage*(75 + 5*skill_lv)/100;
+ damage2 = damage2*(75 + 5*skill_lv)/100;
+ if(sd->arrow_ele > 0) {
+ s_ele = sd->arrow_ele;
+ s_ele_ = sd->arrow_ele;
+ }
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ sd->state.arrow_atk = 1;
+ break;
+ case AC_CHARGEARROW: // チャージアロー
+ if(!sd->state.arrow_atk && sd->arrow_atk > 0) {
+ int arr = rand()%(sd->arrow_atk+1);
+ damage += arr;
+ damage2 += arr;
+ }
+ damage = damage*150/100;
+ damage2 = damage2*150/100;
+ if(sd->arrow_ele > 0) {
+ s_ele = sd->arrow_ele;
+ s_ele_ = sd->arrow_ele;
+ }
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ sd->state.arrow_atk = 1;
+ break;
+ case KN_PIERCE: // ピアース
+ damage = damage*(100+ 10*skill_lv)/100;
+ damage2 = damage2*(100+ 10*skill_lv)/100;
+ hitrate=hitrate*(100+5*skill_lv)/100;
+ div_=t_size+1;
+ damage*=div_;
+ damage2*=div_;
+ break;
+ case KN_SPEARSTAB: // スピアスタブ
+ damage = damage*(100+ 15*skill_lv)/100;
+ damage2 = damage2*(100+ 15*skill_lv)/100;
+ break;
+ case KN_SPEARBOOMERANG: // スピアブーメラン
+ damage = damage*(100+ 50*skill_lv)/100;
+ damage2 = damage2*(100+ 50*skill_lv)/100;
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ break;
+ case KN_BRANDISHSPEAR: // ブランディッシュスピア
+ damage = damage*(100+ 20*skill_lv)/100;
+ damage2 = damage2*(100+ 20*skill_lv)/100;
+ if(skill_lv>3 && wflag==1) damage3+=damage/2;
+ if(skill_lv>6 && wflag==1) damage3+=damage/4;
+ if(skill_lv>9 && wflag==1) damage3+=damage/8;
+ if(skill_lv>6 && wflag==2) damage3+=damage/2;
+ if(skill_lv>9 && wflag==2) damage3+=damage/4;
+ if(skill_lv>9 && wflag==3) damage3+=damage/2;
+ damage +=damage3;
+ if(skill_lv>3 && wflag==1) damage4+=damage2/2;
+ if(skill_lv>6 && wflag==1) damage4+=damage2/4;
+ if(skill_lv>9 && wflag==1) damage4+=damage2/8;
+ if(skill_lv>6 && wflag==2) damage4+=damage2/2;
+ if(skill_lv>9 && wflag==2) damage4+=damage2/4;
+ if(skill_lv>9 && wflag==3) damage4+=damage2/2;
+ damage2 +=damage4;
+ blewcount=0;
+ break;
+ case KN_BOWLINGBASH: // ボウリングバッシュ
+ damage = damage*(100+ 50*skill_lv)/100;
+ damage2 = damage2*(100+ 50*skill_lv)/100;
+ blewcount=0;
+ break;
+ case KN_AUTOCOUNTER:
+ if(battle_config.pc_auto_counter_type&1)
+ hitrate += 20;
+ else
+ hitrate = 1000000;
+ flag=(flag&~BF_SKILLMASK)|BF_NORMAL;
+ break;
+ case AS_SONICBLOW: // ソニックブロウ
+ hitrate+=30; // hitrate +30, thanks to midas
+ damage = damage*(300+ 50*skill_lv)/100;
+ damage2 = damage2*(300+ 50*skill_lv)/100;
+ div_=8;
+ break;
+ case TF_SPRINKLESAND: // 砂まき
+ damage = damage*125/100;
+ damage2 = damage2*125/100;
+ break;
+ case MC_CARTREVOLUTION: // カートレボリューション
+ if(sd->cart_max_weight > 0 && sd->cart_weight > 0) {
+ damage = (damage*(150 + pc_checkskill(sd,BS_WEAPONRESEARCH) + (sd->cart_weight*100/sd->cart_max_weight) ) )/100;
+ damage2 = (damage2*(150 + pc_checkskill(sd,BS_WEAPONRESEARCH) + (sd->cart_weight*100/sd->cart_max_weight) ) )/100;
+ }
+ else {
+ damage = (damage*150)/100;
+ damage2 = (damage2*150)/100;
+ }
+ break;
+ // 以下MOB
+ case NPC_COMBOATTACK: // 多段攻撃
+ div_=skill_get_num(skill_num,skill_lv);
+ damage *= div_;
+ damage2 *= div_;
+ break;
+ case NPC_RANDOMATTACK: // ランダムATK攻撃
+ damage = damage*(50+rand()%150)/100;
+ damage2 = damage2*(50+rand()%150)/100;
+ break;
+ // 属性攻撃(適当)
+ case NPC_WATERATTACK:
+ case NPC_GROUNDATTACK:
+ case NPC_FIREATTACK:
+ case NPC_WINDATTACK:
+ case NPC_POISONATTACK:
+ case NPC_HOLYATTACK:
+ case NPC_DARKNESSATTACK:
+ case NPC_TELEKINESISATTACK:
+ damage = damage*(100+25*skill_lv)/100;
+ damage2 = damage2*(100+25*skill_lv)/100;
+ break;
+ case NPC_GUIDEDATTACK:
+ hitrate = 1000000;
+ break;
+ case NPC_RANGEATTACK:
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ break;
+ case NPC_PIERCINGATT:
+ flag=(flag&~BF_RANGEMASK)|BF_SHORT;
+ break;
+ case RG_BACKSTAP: // バックスタブ
+ if(battle_config.backstab_bow_penalty == 1 && sd->status.weapon == 11){
+ damage = (damage*(300+ 40*skill_lv)/100)/2;
+ damage2 = (damage2*(300+ 40*skill_lv)/100)/2;
+ }else{
+ damage = damage*(300+ 40*skill_lv)/100;
+ damage2 = damage2*(300+ 40*skill_lv)/100;
+ }
+ hitrate = 1000000;
+ break;
+ case RG_RAID: // サプライズアタック
+ damage = damage*(100+ 40*skill_lv)/100;
+ damage2 = damage2*(100+ 40*skill_lv)/100;
+ break;
+ case RG_INTIMIDATE: // インティミデイト
+ damage = damage*(100+ 30*skill_lv)/100;
+ damage2 = damage2*(100+ 30*skill_lv)/100;
+ break;
+ case CR_SHIELDCHARGE: // シールドチャージ
+ damage = damage*(100+ 20*skill_lv)/100;
+ damage2 = damage2*(100+ 20*skill_lv)/100;
+ flag=(flag&~BF_RANGEMASK)|BF_SHORT;
+ s_ele = 0;
+ break;
+ case CR_SHIELDBOOMERANG: // シールドブーメラン
+ damage = damage*(100+ 30*skill_lv)/100;
+ damage2 = damage2*(100+ 30*skill_lv)/100;
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ s_ele = 0;
+ break;
+ case CR_HOLYCROSS: // ホーリークロス
+ damage = damage*(100+ 35*skill_lv)/100;
+ damage2 = damage2*(100+ 35*skill_lv)/100;
+ div_=2;
+ break;
+ case CR_GRANDCROSS:
+ hitrate= 1000000;
+ break;
+ case AM_DEMONSTRATION: // デモンストレーション
+ damage = damage*(100+ 20*skill_lv)/100;
+ damage2 = damage2*(100+ 20*skill_lv)/100;
+ break;
+ case AM_ACIDTERROR: // アシッドテラー
+ damage = damage*(100+ 40*skill_lv)/100;
+ damage2 = damage2*(100+ 40*skill_lv)/100;
+ break;
+ case MO_FINGEROFFENSIVE: //指弾
+ if(battle_config.finger_offensive_type == 0) {
+ damage = damage * (100 + 50 * skill_lv) / 100 * sd->spiritball_old;
+ damage2 = damage2 * (100 + 50 * skill_lv) / 100 * sd->spiritball_old;
+ div_ = sd->spiritball_old;
+ }
+ else {
+ damage = damage * (100 + 50 * skill_lv) / 100;
+ damage2 = damage2 * (100 + 50 * skill_lv) / 100;
+ div_ = 1;
+ }
+ break;
+ case MO_INVESTIGATE: // 発 勁
+ if(def1 < 1000000) {
+ damage = damage*(100+ 75*skill_lv)/100 * (def1 + def2)/100;
+ damage2 = damage2*(100+ 75*skill_lv)/100 * (def1 + def2)/100;
+ }
+ hitrate = 1000000;
+ s_ele = 0;
+ s_ele_ = 0;
+ break;
+ case MO_EXTREMITYFIST: // 阿修羅覇鳳拳
+ damage = damage * (8 + ((sd->status.sp)/10)) + 250 + (skill_lv * 150);
+ damage2 = damage2 * (8 + ((sd->status.sp)/10)) + 250 + (skill_lv * 150);
+ sd->status.sp = 0;
+ clif_updatestatus(sd,SP_SP);
+ hitrate = 1000000;
+ s_ele = 0;
+ s_ele_ = 0;
+ break;
+ case MO_CHAINCOMBO: // 連打掌
+ damage = damage*(150+ 50*skill_lv)/100;
+ damage2 = damage2*(150+ 50*skill_lv)/100;
+ div_=4;
+ break;
+ case MO_COMBOFINISH: // 猛龍拳
+ damage = damage*(240+ 60*skill_lv)/100;
+ damage2 = damage2*(240+ 60*skill_lv)/100;
+ break;
+ case BA_MUSICALSTRIKE: // ミュージカルストライク
+ if(!sd->state.arrow_atk && sd->arrow_atk > 0) {
+ int arr = rand()%(sd->arrow_atk+1);
+ damage += arr;
+ damage2 += arr;
+ }
+ damage = damage*(100+ 50 * skill_lv)/100;
+ damage2 = damage2*(100+ 50 * skill_lv)/100;
+ if(sd->arrow_ele > 0) {
+ s_ele = sd->arrow_ele;
+ s_ele_ = sd->arrow_ele;
+ }
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ sd->state.arrow_atk = 1;
+ break;
+ case DC_THROWARROW: // 矢撃ち
+ if(!sd->state.arrow_atk && sd->arrow_atk > 0) {
+ int arr = rand()%(sd->arrow_atk+1);
+ damage += arr;
+ damage2 += arr;
+ }
+ damage = damage*(100+ 50 * skill_lv)/100;
+ damage2 = damage2*(100+ 50 * skill_lv)/100;
+ if(sd->arrow_ele > 0) {
+ s_ele = sd->arrow_ele;
+ s_ele_ = sd->arrow_ele;
+ }
+ flag=(flag&~BF_RANGEMASK)|BF_LONG;
+ sd->state.arrow_atk = 1;
+ break;
+ case CH_TIGERFIST: // 伏虎拳
+ damage = damage*(100+ 20*skill_lv)/100;
+ damage2 = damage2*(100+ 20*skill_lv)/100;
+ break;
+ case CH_CHAINCRUSH: // 連柱崩撃
+ damage = damage*(100+ 20*skill_lv)/100;
+ damage2 = damage2*(100+ 20*skill_lv)/100;
+ div_=skill_get_num(skill_num,skill_lv);
+ break;
+ case CH_PALMSTRIKE: // 猛虎硬派山
+ damage = damage*(50+ 100*skill_lv)/100;
+ damage2 = damage2*(50+ 100*skill_lv)/100;
+ break;
+ case LK_SPIRALPIERCE: /* スパイラルピアース */
+ damage = damage*(100+ 50*skill_lv)/100; //増加量が分からないので適当に
+ damage2 = damage2*(100+ 50*skill_lv)/100; //増加量が分からないので適当に
+ div_=5;
+ if(tsd)
+ tsd->canmove_tick = gettick() + 1000;
+ else if(tmd)
+ tmd->canmove_tick = gettick() + 1000;
+ break;
+ case LK_HEADCRUSH: /* ヘッドクラッシュ */
+ damage = damage*(100+ 20*skill_lv)/100;
+ damage2 = damage2*(100+ 20*skill_lv)/100;
+ break;
+ case LK_JOINTBEAT: /* ジョイントビート */
+ damage = damage*(50+ 10*skill_lv)/100;
+ damage2 = damage2*(50+ 10*skill_lv)/100;
+ break;
+ case ASC_METEORASSAULT: /* メテオアサルト */
+ damage = damage*(40+ 40*skill_lv)/100;
+ damage2 = damage2*(40+ 40*skill_lv)/100;
+ break;
+ case SN_SHARPSHOOTING: /* シャープシューティング */
+ damage += damage*(30*skill_lv)/100;
+ damage2 += damage2*(30*skill_lv)/100;
+ break;
+ case CG_ARROWVULCAN: /* アローバルカン */
+ damage = damage*(160+40*skill_lv)/100;
+ damage2 = damage2*(160+40*skill_lv)/100;
+ div_=9;
+ break;
+ case AS_SPLASHER: /* ベナムスプラッシャー */
+ damage = damage*(200+20*skill_lv+20*pc_checkskill(sd,AS_POISONREACT))/100;
+ damage2 = damage2*(200+20*skill_lv+20*pc_checkskill(sd,AS_POISONREACT))/100;
+ break;
+ case PA_SACRIFICE:
+ if(sd){
+ int hp, mhp, damage3;
+ hp = battle_get_hp(src);
+ mhp = battle_get_max_hp(src);
+ damage3 = mhp*((skill_lv/2)+(50/100))/100;
+ damage = (((skill_lv*15)+90)/100)*damage3/100;
+ damage2 = (((skill_lv*15)+90)/100)*damage3/100;
+ }
+ break;
+ case ASC_BREAKER: // -- moonsoul (special damage for ASC_BREAKER skill)
+ if(sd){
+ int damage3;
+ int mdef1=battle_get_mdef(target);
+ int mdef2=battle_get_mdef2(target);
+ int imdef_flag=0;
+
+ damage = ((damage * 5) + (skill_lv * battle_get_int(src) * 5) + rand()%500 + 500) /2;
+ damage2 = ((damage2 * 5) + (skill_lv * battle_get_int(src) * 5) + rand()%500 + 500) /2;
+ damage3 = damage;
+ hitrate = 1000000;
+
+ if(sd->ignore_mdef_ele & (1<<t_ele) || sd->ignore_mdef_race & (1<<t_race))
+ imdef_flag = 1;
+ if(t_mode & 0x20) {
+ if(sd->ignore_mdef_race & (1<<10))
+ imdef_flag = 1;
+ }
+ else {
+ if(sd->ignore_mdef_race & (1<<11))
+ imdef_flag = 1;
+ }
+ if(!imdef_flag){
+ if(battle_config.magic_defense_type) {
+ damage3 = damage3 - (mdef1 * battle_config.magic_defense_type) - mdef2;
+ }
+ else{
+ damage3 = (damage3*(100-mdef1))/100 - mdef2;
+ }
+ }
+
+ if(damage3<1)
+ damage3=1;
+
+ damage3=battle_attr_fix(damage2,s_ele_, battle_get_element(target) );
+ }
+ break;
+ }
+ }
+ if(da == 2) { //三段掌が発動しているか
+ type = 0x08;
+ div_ = 255; //三段掌用に…
+ damage = damage * (100 + 20 * pc_checkskill(sd, MO_TRIPLEATTACK)) / 100;
+ }
+
+ if( skill_num!=NPC_CRITICALSLASH ){
+ // 対 象の防御力によるダメージの減少
+ // ディバインプロテクション(ここでいいのかな?)
+ if ( skill_num != MO_INVESTIGATE && skill_num != MO_EXTREMITYFIST && skill_num != KN_AUTOCOUNTER && def1 < 1000000) { //DEF, VIT無視
+ int t_def;
+ target_count = 1 + battle_counttargeted(target,src,battle_config.vit_penaly_count_lv);
+ if(battle_config.vit_penaly_type > 0) {
+ if(target_count >= battle_config.vit_penaly_count) {
+ if(battle_config.vit_penaly_type == 1) {
+ def1 = (def1 * (100 - (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num))/100;
+ def2 = (def2 * (100 - (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num))/100;
+ t_vit = (t_vit * (100 - (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num))/100;
+ }
+ else if(battle_config.vit_penaly_type == 2) {
+ def1 -= (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num;
+ def2 -= (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num;
+ t_vit -= (target_count - (battle_config.vit_penaly_count - 1))*battle_config.vit_penaly_num;
+ }
+ if(def1 < 0) def1 = 0;
+ if(def2 < 1) def2 = 1;
+ if(t_vit < 1) t_vit = 1;
+ }
+ }
+ t_def = def2*8/10;
+ vitbonusmax = (t_vit/20)*(t_vit/20)-1;
+ if(sd->ignore_def_ele & (1<<t_ele) || sd->ignore_def_race & (1<<t_race))
+ idef_flag = 1;
+ if(sd->ignore_def_ele_ & (1<<t_ele) || sd->ignore_def_race_ & (1<<t_race))
+ idef_flag_ = 1;
+ if(t_mode & 0x20) {
+ if(sd->ignore_def_race & (1<<10))
+ idef_flag = 1;
+ if(sd->ignore_def_race_ & (1<<10))
+ idef_flag_ = 1;
+ }
+ else {
+ if(sd->ignore_def_race & (1<<11))
+ idef_flag = 1;
+ if(sd->ignore_def_race_ & (1<<11))
+ idef_flag_ = 1;
+ }
+
+ if(!idef_flag){
+ if(battle_config.player_defense_type) {
+ damage = damage - (def1 * battle_config.player_defense_type) - t_def - ((vitbonusmax < 1)?0: rand()%(vitbonusmax+1) );
+ }
+ else{
+ damage = damage * (100 - def1) /100 - t_def - ((vitbonusmax < 1)?0: rand()%(vitbonusmax+1) );
+ }
+ }
+ if(!idef_flag_){
+ if(battle_config.player_defense_type) {
+ damage2 = damage2 - (def1 * battle_config.player_defense_type) - t_def - ((vitbonusmax < 1)?0: rand()%(vitbonusmax+1) );
+ }
+ else{
+ damage2 = damage2 * (100 - def1) /100 - t_def - ((vitbonusmax < 1)?0: rand()%(vitbonusmax+1) );
+ }
+ }
+ }
+ }
+ }
+ // 精錬ダメージの追加
+ if( skill_num != MO_INVESTIGATE && skill_num != MO_EXTREMITYFIST) { //DEF, VIT無視
+ damage += battle_get_atk2(src);
+ damage2 += battle_get_atk_2(src);
+ }
+ if(skill_num == CR_SHIELDBOOMERANG) {
+ if(sd->equip_index[8] >= 0) {
+ int index = sd->equip_index[8];
+ if(sd->inventory_data[index] && sd->inventory_data[index]->type == 5) {
+ damage += sd->inventory_data[index]->weight/10;
+ damage += sd->status.inventory[index].refine * pc_getrefinebonus(0,1);
+ }
+ }
+ }
+ if(skill_num == LK_SPIRALPIERCE) { /* スパイラルピアース */
+ if(sd->equip_index[9] >= 0) { //重量で追加ダメージらしいのでシールドブーメランを参考に追加
+ int index = sd->equip_index[9];
+ if(sd->inventory_data[index] && sd->inventory_data[index]->type == 4) {
+ damage += (int)(double)(sd->inventory_data[index]->weight*(0.8*skill_lv*4/10));
+ damage += sd->status.inventory[index].refine * pc_getrefinebonus(0,1);
+ }
+ }
+ }
+
+ // 0未満だった場合1に補正
+ if(damage<1) damage=1;
+ if(damage2<1) damage2=1;
+
+ // スキル修正2(修練系)
+ // 修練ダメージ(右手のみ) ソニックブロー時は別処理(1撃に付き1/8適応)
+ if( skill_num != MO_INVESTIGATE && skill_num != MO_EXTREMITYFIST && skill_num != CR_GRANDCROSS) { //修練ダメージ無視
+ damage = battle_addmastery(sd,target,damage,0);
+ damage2 = battle_addmastery(sd,target,damage2,1);
+ }
+
+ if(sd->perfect_hit > 0) {
+ if(rand()%100 < sd->perfect_hit)
+ hitrate = 1000000;
+ }
+
+ // 回避修正
+ hitrate = (hitrate<5)?5:hitrate;
+ if( hitrate < 1000000 && // 必中攻撃
+ (t_sc_data != NULL && (t_sc_data[SC_SLEEP].timer!=-1 || // 睡眠は必中
+ t_sc_data[SC_STAN].timer!=-1 || // スタンは必中
+ t_sc_data[SC_FREEZE].timer!=-1 || (t_sc_data[SC_STONE].timer!=-1 && t_sc_data[SC_STONE].val2==0) ) ) ) // 凍結は必中
+ hitrate = 1000000;
+ if(type == 0 && rand()%100 >= hitrate) {
+ damage = damage2 = 0;
+ dmg_lv = ATK_FLEE;
+ } else {
+ dmg_lv = ATK_DEF;
+ }
+ // スキル修正3(武器研究)
+ if( (skill=pc_checkskill(sd,BS_WEAPONRESEARCH)) > 0) {
+ damage+= skill*2;
+ damage2+= skill*2;
+ }
+ //Advanced Katar Research by zanetheinsane
+ if(sd->weapontype1 == 0x10 || sd->weapontype2 == 0x10){
+ if((skill = pc_checkskill(sd,ASC_KATAR)) > 0) {
+ damage += (damage*((skill*2)+10)) / 100 ;
+ }
+ }
+
+//スキルによるダメージ補正ここまで
+
+//カードによるダメージ追加処理ここから
+ cardfix=100;
+ if(!sd->state.arrow_atk) { //弓矢以外
+ if(!battle_config.left_cardfix_to_right) { //左手カード補正設定無し
+ cardfix=cardfix*(100+sd->addrace[t_race])/100; // 種族によるダメージ修正
+ cardfix=cardfix*(100+sd->addele[t_ele])/100; // 属性によるダメージ修正
+ cardfix=cardfix*(100+sd->addsize[t_size])/100; // サイズによるダメージ修正
+ }
+ else {
+ cardfix=cardfix*(100+sd->addrace[t_race]+sd->addrace_[t_race])/100; // 種族によるダメージ修正(左手による追加あり)
+ cardfix=cardfix*(100+sd->addele[t_ele]+sd->addele_[t_ele])/100; // 属性によるダメージ修正(左手による追加あり)
+ cardfix=cardfix*(100+sd->addsize[t_size]+sd->addsize_[t_size])/100; // サイズによるダメージ修正(左手による追加あり)
+ }
+ }
+ else { //弓矢
+ cardfix=cardfix*(100+sd->addrace[t_race]+sd->arrow_addrace[t_race])/100; // 種族によるダメージ修正(弓矢による追加あり)
+ cardfix=cardfix*(100+sd->addele[t_ele]+sd->arrow_addele[t_ele])/100; // 属性によるダメージ修正(弓矢による追加あり)
+ cardfix=cardfix*(100+sd->addsize[t_size]+sd->arrow_addsize[t_size])/100; // サイズによるダメージ修正(弓矢による追加あり)
+ }
+ if(t_mode & 0x20) { //ボス
+ if(!sd->state.arrow_atk) { //弓矢攻撃以外なら
+ if(!battle_config.left_cardfix_to_right) //左手カード補正設定無し
+ cardfix=cardfix*(100+sd->addrace[10])/100; //ボスモンスターに追加ダメージ
+ else //左手カード補正設定あり
+ cardfix=cardfix*(100+sd->addrace[10]+sd->addrace_[10])/100; //ボスモンスターに追加ダメージ(左手による追加あり)
+ }
+ else //弓矢攻撃
+ cardfix=cardfix*(100+sd->addrace[10]+sd->arrow_addrace[10])/100; //ボスモンスターに追加ダメージ(弓矢による追加あり)
+ }
+ else { //ボスじゃない
+ if(!sd->state.arrow_atk) { //弓矢攻撃以外
+ if(!battle_config.left_cardfix_to_right) //左手カード補正設定無し
+ cardfix=cardfix*(100+sd->addrace[11])/100; //ボス以外モンスターに追加ダメージ
+ else //左手カード補正設定あり
+ cardfix=cardfix*(100+sd->addrace[11]+sd->addrace_[11])/100; //ボス以外モンスターに追加ダメージ(左手による追加あり)
+ }
+ else
+ cardfix=cardfix*(100+sd->addrace[11]+sd->arrow_addrace[11])/100; //ボス以外モンスターに追加ダメージ(弓矢による追加あり)
+ }
+ //特定Class用補正処理(少女の日記→ボンゴン用?)
+ t_class = battle_get_class(target);
+ for(i=0;i<sd->add_damage_class_count;i++) {
+ if(sd->add_damage_classid[i] == t_class) {
+ cardfix=cardfix*(100+sd->add_damage_classrate[i])/100;
+ break;
+ }
+ }
+ if(skill_num != CR_GRANDCROSS || !battle_config.gx_cardfix)
+ damage=damage*cardfix/100; //カード補正によるダメージ増加
+//カードによるダメージ増加処理ここまで
+
+//カードによるダメージ追加処理(左手)ここから
+ cardfix=100;
+ if(!battle_config.left_cardfix_to_right) { //左手カード補正設定無し
+ cardfix=cardfix*(100+sd->addrace_[t_race])/100; // 種族によるダメージ修正左手
+ cardfix=cardfix*(100+sd->addele_[t_ele])/100; // 属 性によるダメージ修正左手
+ cardfix=cardfix*(100+sd->addsize_[t_size])/100; // サイズによるダメージ修正左手
+ if(t_mode & 0x20) //ボス
+ cardfix=cardfix*(100+sd->addrace_[10])/100; //ボスモンスターに追加ダメージ左手
+ else
+ cardfix=cardfix*(100+sd->addrace_[11])/100; //ボス以外モンスターに追加ダメージ左手
+ }
+ //特定Class用補正処理左手(少女の日記→ボンゴン用?)
+ for(i=0;i<sd->add_damage_class_count_;i++) {
+ if(sd->add_damage_classid_[i] == t_class) {
+ cardfix=cardfix*(100+sd->add_damage_classrate_[i])/100;
+ break;
+ }
+ }
+ if(skill_num != CR_GRANDCROSS) damage2=damage2*cardfix/100; //カード補正による左手ダメージ増加
+//カードによるダメージ増加処理(左手)ここまで
+
+// -- moonsoul (cardfix for magic damage portion of ASC_BREAKER)
+ if(skill_num == ASC_BREAKER)
+ damage3 = damage3 * cardfix / 100;
+
+//カードによるダメージ減衰処理ここから
+ if(tsd){ //対象がPCの場合
+ cardfix=100;
+ cardfix=cardfix*(100-tsd->subrace[s_race])/100; // 種族によるダメージ耐性
+ cardfix=cardfix*(100-tsd->subele[s_ele])/100; // 属性によるダメージ耐性
+ if(battle_get_mode(src) & 0x20)
+ cardfix=cardfix*(100-tsd->subrace[10])/100; //ボスからの攻撃はダメージ減少
+ else
+ cardfix=cardfix*(100-tsd->subrace[11])/100; //ボス以外からの攻撃はダメージ減少
+ //特定Class用補正処理左手(少女の日記→ボンゴン用?)
+ for(i=0;i<tsd->add_def_class_count;i++) {
+ if(tsd->add_def_classid[i] == sd->status.class) {
+ cardfix=cardfix*(100-tsd->add_def_classrate[i])/100;
+ break;
+ }
+ }
+ if(flag&BF_LONG)
+ cardfix=cardfix*(100-tsd->long_attack_def_rate)/100; //遠距離攻撃はダメージ減少(ホルンCとか)
+ if(flag&BF_SHORT)
+ cardfix=cardfix*(100-tsd->near_attack_def_rate)/100; //近距離攻撃はダメージ減少(該当無し?)
+ damage=damage*cardfix/100; //カード補正によるダメージ減少
+ damage2=damage2*cardfix/100; //カード補正による左手ダメージ減少
+ }
+//カードによるダメージ減衰処理ここまで
+
+//対象にステータス異常がある場合のダメージ減算処理ここから
+ if(t_sc_data) {
+ cardfix=100;
+ if(t_sc_data[SC_DEFENDER].timer != -1 && flag&BF_LONG) //ディフェンダー状態で遠距離攻撃
+ cardfix=cardfix*(100-t_sc_data[SC_DEFENDER].val2)/100; //ディフェンダーによる減衰
+ if(cardfix != 100) {
+ damage=damage*cardfix/100; //ディフェンダー補正によるダメージ減少
+ damage2=damage2*cardfix/100; //ディフェンダー補正による左手ダメージ減少
+ }
+ if(t_sc_data[SC_ASSUMPTIO].timer != -1){ //アスムプティオ
+ if(!map[target->m].flag.pvp){
+ damage=damage/3;
+ damage2=damage2/3;
+ }else{
+ damage=damage/2;
+ damage2=damage2/2;
+ }
+ }
+ }
+//対象にステータス異常がある場合のダメージ減算処理ここまで
+
+ if(damage < 0) damage = 0;
+ if(damage2 < 0) damage2 = 0;
+
+ // 属 性の適用
+ damage=battle_attr_fix(damage,s_ele, battle_get_element(target) );
+ damage2=battle_attr_fix(damage2,s_ele_, battle_get_element(target) );
+
+ // 星のかけら、気球の適用
+ damage += sd->star;
+ damage2 += sd->star_;
+ damage += sd->spiritball*3;
+ damage2 += sd->spiritball*3;
+
+ if(sc_data && sc_data[SC_AURABLADE].timer!=-1){ /* オーラブレード 必中 */
+ damage += sc_data[SC_AURABLADE].val1 * 10;
+ damage2 += sc_data[SC_AURABLADE].val1 * 10;
+ }
+ if(skill_num==PA_PRESSURE){ /* プレッシャー 必中? */
+ damage = 700+100*skill_lv;
+ damage2 = 700+100*skill_lv;
+ }
+
+ // >二刀流の左右ダメージ計算誰かやってくれぇぇぇぇえええ!
+ // >map_session_data に左手ダメージ(atk,atk2)追加して
+ // >pc_calcstatus()でやるべきかな?
+ // map_session_data に左手武器(atk,atk2,ele,star,atkmods)追加して
+ // pc_calcstatus()でデータを入力しています
+
+ //左手のみ武器装備
+ if(sd->weapontype1 == 0 && sd->weapontype2 > 0) {
+ damage = damage2;
+ damage2 = 0;
+ }
+ // 右手、左手修練の適用
+ if(sd->status.weapon > 16) {// 二刀流か?
+ int dmg = damage, dmg2 = damage2;
+ // 右手修練(60% 〜 100%) 右手全般
+ skill = pc_checkskill(sd,AS_RIGHT);
+ damage = damage * (50 + (skill * 10))/100;
+ if(dmg > 0 && damage < 1) damage = 1;
+ // 左手修練(40% 〜 80%) 左手全般
+ skill = pc_checkskill(sd,AS_LEFT);
+ damage2 = damage2 * (30 + (skill * 10))/100;
+ if(dmg2 > 0 && damage2 < 1) damage2 = 1;
+ }
+ else //二刀流でなければ左手ダメージは0
+ damage2 = 0;
+
+ // 右手,短剣のみ
+ if(da == 1) { //ダブルアタックが発動しているか
+ div_ = 2;
+ damage += damage;
+ type = 0x08;
+ }
+
+ if(sd->status.weapon == 16) {
+ // カタール追撃ダメージ
+ skill = pc_checkskill(sd,TF_DOUBLE);
+ damage2 = damage * (1 + (skill * 2))/100;
+ if(damage > 0 && damage2 < 1) damage2 = 1;
+ }
+
+ // インベナム修正
+ if(skill_num==TF_POISON){
+ damage = battle_attr_fix(damage + 15*skill_lv, s_ele, battle_get_element(target) );
+ }
+ if(skill_num==MC_CARTREVOLUTION){
+ damage = battle_attr_fix(damage, 0, battle_get_element(target) );
+ }
+
+ // 完全回避の判定
+ if(skill_num == 0 && skill_lv >= 0 && tsd!=NULL && div_ < 255 && rand()%1000 < battle_get_flee2(target) ){
+ damage=damage2=0;
+ type=0x0b;
+ dmg_lv = ATK_LUCKY;
+ }
+
+ // 対象が完全回避をする設定がONなら
+ if(battle_config.enemy_perfect_flee) {
+ if(skill_num == 0 && skill_lv >= 0 && tmd!=NULL && div_ < 255 && rand()%1000 < battle_get_flee2(target) ) {
+ damage=damage2=0;
+ type=0x0b;
+ dmg_lv = ATK_LUCKY;
+ }
+ }
+
+ //MobのModeに頑強フラグが立っているときの処理
+ if(t_mode&0x40){
+ if(damage > 0)
+ damage = 1;
+ if(damage2 > 0)
+ damage2 = 1;
+ }
+
+ //bNoWeaponDamage(設定アイテム無し?)でグランドクロスじゃない場合はダメージが0
+ if( tsd && tsd->special_state.no_weapon_damage && skill_num != CR_GRANDCROSS)
+ damage = damage2 = 0;
+
+ if(skill_num != CR_GRANDCROSS && (damage > 0 || damage2 > 0) ) {
+ if(damage2<1) // ダメージ最終修正
+ damage=battle_calc_damage(src,target,damage,div_,skill_num,skill_lv,flag);
+ else if(damage<1) // 右手がミス?
+ damage2=battle_calc_damage(src,target,damage2,div_,skill_num,skill_lv,flag);
+ else { // 両 手/カタールの場合はちょっと計算ややこしい
+ int d1=damage+damage2,d2=damage2;
+ damage=battle_calc_damage(src,target,damage+damage2,div_,skill_num,skill_lv,flag);
+ damage2=(d2*100/d1)*damage/100;
+ if(damage > 1 && damage2 < 1) damage2=1;
+ damage-=damage2;
+ }
+ }
+
+ /* For executioner card [Valaris] */
+ if(src->type == BL_PC && sd->random_attack_increase_add > 0 && sd->random_attack_increase_per > 0 && skill_num == 0 ){
+ if(rand()%100 < sd->random_attack_increase_per){
+ if(damage >0) damage*=sd->random_attack_increase_add/100;
+ if(damage2 >0) damage2*=sd->random_attack_increase_add/100;
+ }
+ }
+ /* End addition */
+
+// -- moonsoul (final combination of phys, mag damage for ASC_BREAKER)
+ if(skill_num == ASC_BREAKER) {
+ damage += damage3;
+ damage2 += damage3;
+ }
+
+ wd.damage=damage;
+ wd.damage2=damage2;
+ wd.type=type;
+ wd.div_=div_;
+ wd.amotion=battle_get_amotion(src);
+ if(skill_num == KN_AUTOCOUNTER)
+ wd.amotion >>= 1;
+ wd.dmotion=battle_get_dmotion(target);
+ wd.blewcount=blewcount;
+ wd.flag=flag;
+ wd.dmg_lv=dmg_lv;
+
+ return wd;
+}
+
+/*==========================================
+ * 武器ダメージ計算
+ *------------------------------------------
+ */
+struct Damage battle_calc_weapon_attack(
+ struct block_list *src,struct block_list *target,int skill_num,int skill_lv,int wflag)
+{
+ struct Damage wd;
+
+ //return前の処理があるので情報出力部のみ変更
+ if (src == NULL || target == NULL) {
+ nullpo_info(NLP_MARK);
+ memset(&wd,0,sizeof(wd));
+ return wd;
+ }
+
+ if(target->type == BL_PET)
+ memset(&wd,0,sizeof(wd));
+
+ else if(src->type == BL_PC)
+ wd = battle_calc_pc_weapon_attack(src,target,skill_num,skill_lv,wflag);
+ else if(src->type == BL_MOB)
+ wd = battle_calc_mob_weapon_attack(src,target,skill_num,skill_lv,wflag);
+ else if(src->type == BL_PET)
+ wd = battle_calc_pet_weapon_attack(src,target,skill_num,skill_lv,wflag);
+ else
+ memset(&wd,0,sizeof(wd));
+
+ if(battle_config.equipment_breaking && src->type==BL_PC && (wd.damage > 0 || wd.damage2 > 0)) {
+ struct map_session_data *sd=(struct map_session_data *)src;
+ int breakrate=1;
+ if(sd->status.weapon && sd->status.weapon!=11) {
+ if(target->type == BL_PC && sd->sc_data[SC_MELTDOWN].timer!=-1){
+ breakrate+=100*sd->sc_data[SC_MELTDOWN].val1;
+ if(rand()%10000 < breakrate*battle_config.equipment_break_rate/100 || breakrate >= 10000)
+ pc_breakweapon((struct map_session_data *)target);
+ }
+ if(sd->sc_data[SC_OVERTHRUST].timer!=-1)
+ breakrate+=20*sd->sc_data[SC_OVERTHRUST].val1;
+ if(wd.type==0x0a)
+ breakrate*=2;
+ if(rand()%10000 < breakrate*battle_config.equipment_break_rate/100 || breakrate >= 10000) {
+ if(pc_breakweapon(sd)==1)
+ wd = battle_calc_pc_weapon_attack(src,target,skill_num,skill_lv,wflag);
+ }
+ }
+ }
+
+ if (battle_config.equipment_breaking && target->type == BL_PC && (wd.damage > 0 || wd.damage2 > 0)) {
+ int breakrate=1;
+ if(src->type==BL_PC && ((struct map_session_data *)src)->sc_data[SC_MELTDOWN].timer!=-1) breakrate+=70*((struct map_session_data *)src)->sc_data[SC_MELTDOWN].val1;
+ if (wd.type==0x0a)
+ breakrate*=2;
+ if (rand()%10000 < breakrate*battle_config.equipment_break_rate/100 || breakrate >= 10000) {
+ pc_breakarmor((struct map_session_data *)target);
+ }
+ }
+
+ return wd;
+}
+
+/*==========================================
+ * 魔法ダメージ計算
+ *------------------------------------------
+ */
+struct Damage battle_calc_magic_attack(
+ struct block_list *bl,struct block_list *target,int skill_num,int skill_lv,int flag)
+ {
+ int mdef1=battle_get_mdef(target);
+ int mdef2=battle_get_mdef2(target);
+ int matk1,matk2,damage=0,div_=1,blewcount=skill_get_blewcount(skill_num,skill_lv),rdamage = 0;
+ struct Damage md;
+ int aflag;
+ int normalmagic_flag=1;
+ int ele=0,race=7,t_ele=0,t_race=7,t_mode = 0,cardfix,t_class,i;
+ struct map_session_data *sd=NULL,*tsd=NULL;
+ struct mob_data *tmd = NULL;
+
+
+ //return前の処理があるので情報出力部のみ変更
+ if( bl == NULL || target == NULL ){
+ nullpo_info(NLP_MARK);
+ memset(&md,0,sizeof(md));
+ return md;
+ }
+
+ if(target->type == BL_PET) {
+ memset(&md,0,sizeof(md));
+ return md;
+ }
+
+ matk1=battle_get_matk1(bl);
+ matk2=battle_get_matk2(bl);
+ ele = skill_get_pl(skill_num);
+ race = battle_get_race(bl);
+ t_ele = battle_get_elem_type(target);
+ t_race = battle_get_race(target);
+ t_mode = battle_get_mode(target);
+
+#define MATK_FIX( a,b ) { matk1=matk1*(a)/(b); matk2=matk2*(a)/(b); }
+
+ if( bl->type==BL_PC && (sd=(struct map_session_data *)bl) ){
+ sd->state.attack_type = BF_MAGIC;
+ if(sd->matk_rate != 100)
+ MATK_FIX(sd->matk_rate,100);
+ sd->state.arrow_atk = 0;
+ }
+ if( target->type==BL_PC )
+ tsd=(struct map_session_data *)target;
+ else if( target->type==BL_MOB )
+ tmd=(struct mob_data *)target;
+
+ aflag=BF_MAGIC|BF_LONG|BF_SKILL;
+
+ if(skill_num > 0){
+ switch(skill_num){ // 基本ダメージ計算(スキルごとに処理)
+ // ヒールor聖体
+ case AL_HEAL:
+ case PR_BENEDICTIO:
+ damage = skill_calc_heal(bl,skill_lv)/2;
+ normalmagic_flag=0;
+ break;
+ case PR_ASPERSIO: /* アスペルシオ */
+ damage = 40; //固定ダメージ
+ normalmagic_flag=0;
+ break;
+ case PR_SANCTUARY: // サンクチュアリ
+ damage = (skill_lv>6)?388:skill_lv*50;
+ normalmagic_flag=0;
+ blewcount|=0x10000;
+ break;
+ case ALL_RESURRECTION:
+ case PR_TURNUNDEAD: // 攻撃リザレクションとターンアンデッド
+ if(target->type != BL_PC && battle_check_undead(t_race,t_ele)){
+ int hp, mhp, thres;
+ hp = battle_get_hp(target);
+ mhp = battle_get_max_hp(target);
+ thres = (skill_lv * 20) + battle_get_luk(bl)+
+ battle_get_int(bl) + battle_get_lv(bl)+
+ ((200 - hp * 200 / mhp));
+ if(thres > 700) thres = 700;
+// if(battle_config.battle_log)
+// printf("ターンアンデッド! 確率%d ‰(千分率)\n", thres);
+ if(rand()%1000 < thres && !(t_mode&0x20)) // 成功
+ damage = hp;
+ else // 失敗
+ damage = battle_get_lv(bl) + battle_get_int(bl) + skill_lv * 10;
+ }
+ normalmagic_flag=0;
+ break;
+
+ case MG_NAPALMBEAT: // ナパームビート(分散計算込み)
+ MATK_FIX(70+ skill_lv*10,100);
+ if(flag>0){
+ MATK_FIX(1,flag);
+ }else {
+ if(battle_config.error_log)
+ printf("battle_calc_magic_attack(): napam enemy count=0 !\n");
+ }
+ break;
+ case MG_FIREBALL: // ファイヤーボール
+ {
+ const int drate[]={100,90,70};
+ if(flag>2)
+ matk1=matk2=0;
+ else
+ MATK_FIX( (95+skill_lv*5)*drate[flag] ,10000 );
+ }
+ break;
+ case MG_FIREWALL: // ファイヤーウォール
+/*
+ if( (t_ele!=3 && !battle_check_undead(t_race,t_ele)) || target->type==BL_PC ) //PCは火属性でも飛ぶ?そもそもダメージ受ける?
+ blewcount |= 0x10000;
+ else
+ blewcount = 0;
+*/
+ if((t_ele==3 || battle_check_undead(t_race,t_ele)) && target->type!=BL_PC)
+ blewcount = 0;
+ else
+ blewcount |= 0x10000;
+ MATK_FIX( 1,2 );
+ break;
+ case MG_THUNDERSTORM: // サンダーストーム
+ MATK_FIX( 80,100 );
+ break;
+ case MG_FROSTDIVER: // フロストダイバ
+ MATK_FIX( 100+skill_lv*10, 100);
+ break;
+ case WZ_FROSTNOVA: // フロストダイバ
+ MATK_FIX( ((100+skill_lv*10)*(2/3)), 100);
+ break;
+ case WZ_FIREPILLAR: // ファイヤーピラー
+ if(mdef1 < 1000000)
+ mdef1=mdef2=0; // MDEF無視
+ MATK_FIX( 1,5 );
+ matk1+=50;
+ matk2+=50;
+ break;
+ case WZ_SIGHTRASHER:
+ MATK_FIX( 100+skill_lv*20, 100);
+ break;
+ case WZ_METEOR:
+ case WZ_JUPITEL: // ユピテルサンダー
+ break;
+ case WZ_VERMILION: // ロードオブバーミリオン
+ MATK_FIX( skill_lv*20+80, 100 );
+ break;
+ case WZ_WATERBALL: // ウォーターボール
+ //matk1+= skill_lv*30;
+ //matk2+= skill_lv*30;
+ MATK_FIX( 100+skill_lv*30, 100 );
+ break;
+ case WZ_STORMGUST: // ストームガスト
+ MATK_FIX( skill_lv*40+100 ,100 );
+ blewcount|=0x10000;
+ break;
+ case AL_HOLYLIGHT: // ホーリーライト
+ MATK_FIX( 125,100 );
+ break;
+ case AL_RUWACH:
+ MATK_FIX( 145,100 );
+ break;
+ case HW_NAPALMVULCAN: // ナパームビート(分散計算込み)
+ MATK_FIX(70+ skill_lv*10,100);
+ if(flag>0){
+ MATK_FIX(1,flag);
+ }else {
+ if(battle_config.error_log)
+ printf("battle_calc_magic_attack(): napalmvulcan enemy count=0 !\n");
+ }
+ break;
+ }
+ }
+
+ if(normalmagic_flag){ // 一般魔法ダメージ計算
+ int imdef_flag=0;
+ if(matk1>matk2)
+ damage= matk2+rand()%(matk1-matk2+1);
+ else
+ damage= matk2;
+ if(sd) {
+ if(sd->ignore_mdef_ele & (1<<t_ele) || sd->ignore_mdef_race & (1<<t_race))
+ imdef_flag = 1;
+ if(t_mode & 0x20) {
+ if(sd->ignore_mdef_race & (1<<10))
+ imdef_flag = 1;
+ }
+ else {
+ if(sd->ignore_mdef_race & (1<<11))
+ imdef_flag = 1;
+ }
+ }
+ if(!imdef_flag){
+ if(battle_config.magic_defense_type) {
+ damage = damage - (mdef1 * battle_config.magic_defense_type) - mdef2;
+ }
+ else{
+ damage = (damage*(100-mdef1))/100 - mdef2;
+ }
+ }
+
+ if(damage<1)
+ damage=1;
+ }
+
+ if(sd) {
+ cardfix=100;
+ cardfix=cardfix*(100+sd->magic_addrace[t_race])/100;
+ cardfix=cardfix*(100+sd->magic_addele[t_ele])/100;
+ if(t_mode & 0x20)
+ cardfix=cardfix*(100+sd->magic_addrace[10])/100;
+ else
+ cardfix=cardfix*(100+sd->magic_addrace[11])/100;
+ t_class = battle_get_class(target);
+ for(i=0;i<sd->add_magic_damage_class_count;i++) {
+ if(sd->add_magic_damage_classid[i] == t_class) {
+ cardfix=cardfix*(100+sd->add_magic_damage_classrate[i])/100;
+ break;
+ }
+ }
+ damage=damage*cardfix/100;
+ }
+
+ if( tsd ){
+ int s_class = battle_get_class(bl);
+ cardfix=100;
+ cardfix=cardfix*(100-tsd->subele[ele])/100; // 属 性によるダメージ耐性
+ cardfix=cardfix*(100-tsd->subrace[race])/100; // 種族によるダメージ耐性
+ cardfix=cardfix*(100-tsd->magic_subrace[race])/100;
+ if(battle_get_mode(bl) & 0x20)
+ cardfix=cardfix*(100-tsd->magic_subrace[10])/100;
+ else
+ cardfix=cardfix*(100-tsd->magic_subrace[11])/100;
+ for(i=0;i<tsd->add_mdef_class_count;i++) {
+ if(tsd->add_mdef_classid[i] == s_class) {
+ cardfix=cardfix*(100-tsd->add_mdef_classrate[i])/100;
+ break;
+ }
+ }
+ cardfix=cardfix*(100-tsd->magic_def_rate)/100;
+ damage=damage*cardfix/100;
+ }
+ if(damage < 0) damage = 0;
+
+ damage=battle_attr_fix(damage, ele, battle_get_element(target) ); // 属 性修正
+
+ if(skill_num == CR_GRANDCROSS) { // グランドクロス
+ struct Damage wd;
+ wd=battle_calc_weapon_attack(bl,target,skill_num,skill_lv,flag);
+ damage = (damage + wd.damage) * (100 + 40*skill_lv)/100;
+ if(battle_config.gx_dupele) damage=battle_attr_fix(damage, ele, battle_get_element(target) ); //属性2回かかる
+ if(bl==target) damage=damage/2; //反動は半分
+ }
+
+ div_=skill_get_num( skill_num,skill_lv );
+
+ if(div_>1 && skill_num != WZ_VERMILION)
+ damage*=div_;
+
+// if(mdef1 >= 1000000 && damage > 0)
+ if(t_mode&0x40 && damage > 0)
+ damage = 1;
+
+ if( tsd && tsd->special_state.no_magic_damage) {
+ if (battle_config.gtb_pvp_only != 0) { // [MouseJstr]
+ if ((map[target->m].flag.pvp || map[target->m].flag.gvg) && target->type==BL_PC)
+ damage = (damage * (100 - battle_config.gtb_pvp_only)) / 100;
+ } else
+ damage=0; // 黄 金蟲カード(魔法ダメージ0)
+ }
+
+ damage=battle_calc_damage(bl,target,damage,div_,skill_num,skill_lv,aflag); // 最終修正
+
+ /* magic_damage_return by [AppleGirl] and [Valaris] */
+ if( target->type==BL_PC && tsd && tsd->magic_damage_return > 0 ){
+ rdamage += damage * tsd->magic_damage_return / 100;
+ if(rdamage < 1) rdamage = 1;
+ clif_damage(target,bl,gettick(),0,0,rdamage,0,0,0);
+ battle_damage(target,bl,rdamage,0);
+ }
+ /* end magic_damage_return */
+
+ md.damage=damage;
+ md.div_=div_;
+ md.amotion=battle_get_amotion(bl);
+ md.dmotion=battle_get_dmotion(target);
+ md.damage2=0;
+ md.type=0;
+ md.blewcount=blewcount;
+ md.flag=aflag;
+
+ return md;
+}
+
+/*==========================================
+ * その他ダメージ計算
+ *------------------------------------------
+ */
+struct Damage battle_calc_misc_attack(
+ struct block_list *bl,struct block_list *target,int skill_num,int skill_lv,int flag)
+{
+ int int_=battle_get_int(bl);
+// int luk=battle_get_luk(bl);
+ int dex=battle_get_dex(bl);
+ int skill,ele,race,cardfix;
+ struct map_session_data *sd=NULL,*tsd=NULL;
+ int damage=0,div_=1,blewcount=skill_get_blewcount(skill_num,skill_lv);
+ struct Damage md;
+ int damagefix=1;
+
+ int aflag=BF_MISC|BF_LONG|BF_SKILL;
+
+ //return前の処理があるので情報出力部のみ変更
+ if( bl == NULL || target == NULL ){
+ nullpo_info(NLP_MARK);
+ memset(&md,0,sizeof(md));
+ return md;
+ }
+
+ if(target->type == BL_PET) {
+ memset(&md,0,sizeof(md));
+ return md;
+ }
+
+ if( bl->type == BL_PC && (sd=(struct map_session_data *)bl) ) {
+ sd->state.attack_type = BF_MISC;
+ sd->state.arrow_atk = 0;
+ }
+
+ if( target->type==BL_PC )
+ tsd=(struct map_session_data *)target;
+
+ switch(skill_num){
+
+ case HT_LANDMINE: // ランドマイン
+ damage=skill_lv*(dex+75)*(100+int_)/100;
+ break;
+
+ case HT_BLASTMINE: // ブラストマイン
+ damage=skill_lv*(dex/2+50)*(100+int_)/100;
+ break;
+
+ case HT_CLAYMORETRAP: // クレイモアートラップ
+ damage=skill_lv*(dex/2+75)*(100+int_)/100;
+ break;
+
+ case HT_BLITZBEAT: // ブリッツビート
+ if( sd==NULL || (skill = pc_checkskill(sd,HT_STEELCROW)) <= 0)
+ skill=0;
+ damage=(dex/10+int_/2+skill*3+40)*2;
+ if(flag > 1)
+ damage /= flag;
+ break;
+
+ case TF_THROWSTONE: // 石投げ
+ damage=50;
+ damagefix=0;
+ break;
+
+ case BA_DISSONANCE: // 不協和音
+ damage=(skill_lv)*20+pc_checkskill(sd,BA_MUSICALLESSON)*3;
+ break;
+
+ case NPC_SELFDESTRUCTION: // 自爆
+ damage=battle_get_hp(bl)-(bl==target?1:0);
+ damagefix=0;
+ break;
+
+ case NPC_SMOKING: // タバコを吸う
+ damage=3;
+ damagefix=0;
+ break;
+
+ case NPC_DARKBREATH:
+ {
+ struct status_change *sc_data = battle_get_sc_data(target);
+ int hitrate=battle_get_hit(bl) - battle_get_flee(target) + 80;
+ hitrate = ( (hitrate>95)?95: ((hitrate<5)?5:hitrate) );
+ if(sc_data && (sc_data[SC_SLEEP].timer!=-1 || sc_data[SC_STAN].timer!=-1 ||
+ sc_data[SC_FREEZE].timer!=-1 || (sc_data[SC_STONE].timer!=-1 && sc_data[SC_STONE].val2==0) ) )
+ hitrate = 1000000;
+ if(rand()%100 < hitrate) {
+ damage = 500 + (skill_lv-1)*1000 + rand()%1000;
+ if(damage > 9999) damage = 9999;
+ }
+ }
+ break;
+ case SN_FALCONASSAULT: /* ファルコンアサルト */
+ skill = pc_checkskill(sd,HT_BLITZBEAT);
+ damage=(100+50*skill_lv+(dex/10+int_/2+skill*3+40)*2);
+ break;
+ }
+
+ ele = skill_get_pl(skill_num);
+ race = battle_get_race(bl);
+
+ if(damagefix){
+ if(damage<1 && skill_num != NPC_DARKBREATH)
+ damage=1;
+
+ if( tsd ){
+ cardfix=100;
+ cardfix=cardfix*(100-tsd->subele[ele])/100; // 属性によるダメージ耐性
+ cardfix=cardfix*(100-tsd->subrace[race])/100; // 種族によるダメージ耐性
+ cardfix=cardfix*(100-tsd->misc_def_rate)/100;
+ damage=damage*cardfix/100;
+ }
+ if(damage < 0) damage = 0;
+ damage=battle_attr_fix(damage, ele, battle_get_element(target) ); // 属性修正
+ }
+
+ div_=skill_get_num( skill_num,skill_lv );
+ if(div_>1)
+ damage*=div_;
+
+ if(damage > 0 && (damage < div_ || (battle_get_def(target) >= 1000000 && battle_get_mdef(target) >= 1000000) ) ) {
+ damage = div_;
+ }
+
+ damage=battle_calc_damage(bl,target,damage,div_,skill_num,skill_lv,aflag); // 最終修正
+
+ md.damage=damage;
+ md.div_=div_;
+ md.amotion=battle_get_amotion(bl);
+ md.dmotion=battle_get_dmotion(target);
+ md.damage2=0;
+ md.type=0;
+ md.blewcount=blewcount;
+ md.flag=aflag;
+ return md;
+
+}
+/*==========================================
+ * ダメージ計算一括処理用
+ *------------------------------------------
+ */
+struct Damage battle_calc_attack( int attack_type,
+ struct block_list *bl,struct block_list *target,int skill_num,int skill_lv,int flag)
+{
+ struct Damage d;
+ switch(attack_type){
+ case BF_WEAPON:
+ return battle_calc_weapon_attack(bl,target,skill_num,skill_lv,flag);
+ case BF_MAGIC:
+ return battle_calc_magic_attack(bl,target,skill_num,skill_lv,flag);
+ case BF_MISC:
+ return battle_calc_misc_attack(bl,target,skill_num,skill_lv,flag);
+ default:
+ if(battle_config.error_log)
+ printf("battle_calc_attack: unknwon attack type ! %d\n",attack_type);
+ break;
+ }
+ return d;
+}
+/*==========================================
+ * 通常攻撃処理まとめ
+ *------------------------------------------
+ */
+int battle_weapon_attack( struct block_list *src,struct block_list *target,
+ unsigned int tick,int flag)
+{
+ struct map_session_data *sd=NULL;
+ struct status_change *sc_data = battle_get_sc_data(src),*t_sc_data=battle_get_sc_data(target);
+ short *opt1;
+ int race = 7, ele = 0;
+ int damage,rdamage = 0;
+ struct Damage wd;
+
+ nullpo_retr(0, src);
+ nullpo_retr(0, target);
+
+ if(src->type == BL_PC)
+ sd = (struct map_session_data *)src;
+
+ if(src->prev == NULL || target->prev == NULL)
+ return 0;
+ if(src->type == BL_PC && pc_isdead(sd))
+ return 0;
+ if(target->type == BL_PC && pc_isdead((struct map_session_data *)target))
+ return 0;
+
+ opt1=battle_get_opt1(src);
+ if(opt1 && *opt1 > 0) {
+ battle_stopattack(src);
+ return 0;
+ }
+ if(sc_data && sc_data[SC_BLADESTOP].timer!=-1){
+ battle_stopattack(src);
+ return 0;
+ }
+
+ race = battle_get_race(target);
+ ele = battle_get_elem_type(target);
+ if(battle_check_target(src,target,BCT_ENEMY) > 0 &&
+ battle_check_range(src,target,0)){
+ // 攻撃対象となりうるので攻撃
+ if(sd && sd->status.weapon == 11) {
+ if(sd->equip_index[10] >= 0) {
+ if(battle_config.arrow_decrement)
+ pc_delitem(sd,sd->equip_index[10],1,0);
+ }
+ else {
+ clif_arrow_fail(sd,0);
+ return 0;
+ }
+ }
+ if(flag&0x8000) {
+ if(sd && battle_config.pc_attack_direction_change)
+ sd->dir = sd->head_dir = map_calc_dir(src, target->x,target->y );
+ else if(src->type == BL_MOB && battle_config.monster_attack_direction_change)
+ ((struct mob_data *)src)->dir = map_calc_dir(src, target->x,target->y );
+ wd=battle_calc_weapon_attack(src,target,KN_AUTOCOUNTER,flag&0xff,0);
+ }
+ else
+ wd=battle_calc_weapon_attack(src,target,0,0,0);
+ if((damage = wd.damage + wd.damage2) > 0 && src != target) {
+ if(wd.flag&BF_SHORT) {
+ if(target->type == BL_PC) {
+ struct map_session_data *tsd = (struct map_session_data *)target;
+ if(tsd && tsd->short_weapon_damage_return > 0) {
+ rdamage += damage * tsd->short_weapon_damage_return / 100;
+ if(rdamage < 1) rdamage = 1;
+ }
+ }
+ if(t_sc_data && t_sc_data[SC_REFLECTSHIELD].timer != -1) {
+ rdamage += damage * t_sc_data[SC_REFLECTSHIELD].val2 / 100;
+ if(rdamage < 1) rdamage = 1;
+ }
+ }
+ else if(wd.flag&BF_LONG) {
+ if(target->type == BL_PC) {
+ struct map_session_data *tsd = (struct map_session_data *)target;
+ if(tsd && tsd->long_weapon_damage_return > 0) {
+ rdamage += damage * tsd->long_weapon_damage_return / 100;
+ if(rdamage < 1) rdamage = 1;
+ }
+ }
+ }
+ if(rdamage > 0)
+ clif_damage(src,src,tick, wd.amotion,0,rdamage,1,4,0);
+ }
+
+ if (wd.div_ == 255 && sd) { //三段掌
+ int delay = 1000 - 4 * battle_get_agi(src) - 2 * battle_get_dex(src);
+ int skilllv;
+ if(wd.damage+wd.damage2 < battle_get_hp(target)) {
+ if((skilllv = pc_checkskill(sd, MO_CHAINCOMBO)) > 0)
+ delay += 300 * battle_config.combo_delay_rate /100; //追加ディレイをconfにより調整
+
+ skill_status_change_start(src,SC_COMBO,MO_TRIPLEATTACK,skilllv,0,0,delay,0);
+ }
+ sd->attackabletime = sd->canmove_tick = tick + delay;
+ clif_combo_delay(src,delay);
+ clif_skill_damage(src , target , tick , wd.amotion , wd.dmotion ,
+ wd.damage , 3 , MO_TRIPLEATTACK, pc_checkskill(sd,MO_TRIPLEATTACK) , -1 );
+ }
+ else {
+ clif_damage(src,target,tick, wd.amotion, wd.dmotion,
+ wd.damage, wd.div_ , wd.type, wd.damage2);
+ //二刀流左手とカタール追撃のミス表示(無理やり〜)
+ if(sd && sd->status.weapon >= 16 && wd.damage2 == 0)
+ clif_damage(src,target,tick+10, wd.amotion, wd.dmotion,0, 1, 0, 0);
+ }
+ if(sd && sd->splash_range > 0 && (wd.damage > 0 || wd.damage2 > 0) )
+ skill_castend_damage_id(src,target,0,-1,tick,0);
+ map_freeblock_lock();
+ battle_damage(src,target,(wd.damage+wd.damage2),0);
+ if(target->prev != NULL &&
+ (target->type != BL_PC || (target->type == BL_PC && !pc_isdead((struct map_session_data *)target) ) ) ) {
+ if(wd.damage > 0 || wd.damage2 > 0) {
+ skill_additional_effect(src,target,0,0,BF_WEAPON,tick);
+ if(sd) {
+ if(sd->weapon_coma_ele[ele] > 0 && rand()%10000 < sd->weapon_coma_ele[ele])
+ battle_damage(src,target,battle_get_max_hp(target),1);
+ if(sd->weapon_coma_race[race] > 0 && rand()%10000 < sd->weapon_coma_race[race])
+ battle_damage(src,target,battle_get_max_hp(target),1);
+ if(battle_get_mode(target) & 0x20) {
+ if(sd->weapon_coma_race[10] > 0 && rand()%10000 < sd->weapon_coma_race[10])
+ battle_damage(src,target,battle_get_max_hp(target),1);
+ }
+ else {
+ if(sd->weapon_coma_race[11] > 0 && rand()%10000 < sd->weapon_coma_race[11])
+ battle_damage(src,target,battle_get_max_hp(target),1);
+ }
+ }
+ }
+ }
+ if(sc_data && sc_data[SC_AUTOSPELL].timer != -1 && rand()%100 < sc_data[SC_AUTOSPELL].val4) {
+ int skilllv=sc_data[SC_AUTOSPELL].val3,i,f=0;
+ i = rand()%100;
+ if(i >= 50) skilllv -= 2;
+ else if(i >= 15) skilllv--;
+ if(skilllv < 1) skilllv = 1;
+ if(sd) {
+ int sp = skill_get_sp(sc_data[SC_AUTOSPELL].val2,skilllv)*2/3;
+ if(sd->status.sp >= sp) {
+ if((i=skill_get_inf(sc_data[SC_AUTOSPELL].val2) == 2) || i == 32)
+ f = skill_castend_pos2(src,target->x,target->y,sc_data[SC_AUTOSPELL].val2,skilllv,tick,flag);
+ else {
+ switch( skill_get_nk(sc_data[SC_AUTOSPELL].val2) ) {
+ case 0: case 2:
+ f = skill_castend_damage_id(src,target,sc_data[SC_AUTOSPELL].val2,skilllv,tick,flag);
+ break;
+ case 1:/* 支援系 */
+ if((sc_data[SC_AUTOSPELL].val2==AL_HEAL || (sc_data[SC_AUTOSPELL].val2==ALL_RESURRECTION && target->type != BL_PC)) && battle_check_undead(race,ele))
+ f = skill_castend_damage_id(src,target,sc_data[SC_AUTOSPELL].val2,skilllv,tick,flag);
+ else
+ f = skill_castend_nodamage_id(src,target,sc_data[SC_AUTOSPELL].val2,skilllv,tick,flag);
+ break;
+ }
+ }
+ if(!f) pc_heal(sd,0,-sp);
+ }
+ }
+ else {
+ if((i=skill_get_inf(sc_data[SC_AUTOSPELL].val2) == 2) || i == 32)
+ skill_castend_pos2(src,target->x,target->y,sc_data[SC_AUTOSPELL].val2,skilllv,tick,flag);
+ else {
+ switch( skill_get_nk(sc_data[SC_AUTOSPELL].val2) ) {
+ case 0: case 2:
+ skill_castend_damage_id(src,target,sc_data[SC_AUTOSPELL].val2,skilllv,tick,flag);
+ break;
+ case 1:/* 支援系 */
+ if((sc_data[SC_AUTOSPELL].val2==AL_HEAL || (sc_data[SC_AUTOSPELL].val2==ALL_RESURRECTION && target->type != BL_PC)) && battle_check_undead(race,ele))
+ skill_castend_damage_id(src,target,sc_data[SC_AUTOSPELL].val2,skilllv,tick,flag);
+ else
+ skill_castend_nodamage_id(src,target,sc_data[SC_AUTOSPELL].val2,skilllv,tick,flag);
+ break;
+ }
+ }
+ }
+ }
+ if(sd) {
+ if(sd->autospell_id > 0 && sd->autospell_lv > 0 && rand()%100 < sd->autospell_rate) {
+ int skilllv=sd->autospell_lv,i,f=0,sp;
+ i = rand()%100;
+ if(i >= 50) skilllv -= 2;
+ else if(i >= 15) skilllv--;
+ if(skilllv < 1) skilllv = 1;
+ sp = skill_get_sp(sd->autospell_id,skilllv)*2/3;
+ if(sd->status.sp >= sp) {
+ if((i=skill_get_inf(sd->autospell_id) == 2) || i == 32)
+ f = skill_castend_pos2(src,target->x,target->y,sd->autospell_id,skilllv,tick,flag);
+ else {
+ switch( skill_get_nk(sd->autospell_id) ) {
+ case 0: case 2:
+ f = skill_castend_damage_id(src,target,sd->autospell_id,skilllv,tick,flag);
+ break;
+ case 1:/* 支援系 */
+ if((sd->autospell_id==AL_HEAL || (sd->autospell_id==ALL_RESURRECTION && target->type != BL_PC)) && battle_check_undead(race,ele))
+ f = skill_castend_damage_id(src,target,sd->autospell_id,skilllv,tick,flag);
+ else
+ f = skill_castend_nodamage_id(src,target,sd->autospell_id,skilllv,tick,flag);
+ break;
+ }
+ }
+ if(!f) pc_heal(sd,0,-sp);
+ }
+ }
+ if(wd.flag&BF_WEAPON && src != target && (wd.damage > 0 || wd.damage2 > 0)) {
+ int hp = 0,sp = 0;
+ if(sd->hp_drain_rate && sd->hp_drain_per > 0 && wd.damage > 0 && rand()%100 < sd->hp_drain_rate) {
+ hp += (wd.damage * sd->hp_drain_per)/100;
+ if(sd->hp_drain_rate > 0 && hp < 1) hp = 1;
+ else if(sd->hp_drain_rate < 0 && hp > -1) hp = -1;
+ }
+ if(sd->hp_drain_rate_ && sd->hp_drain_per_ > 0 && wd.damage2 > 0 && rand()%100 < sd->hp_drain_rate_) {
+ hp += (wd.damage2 * sd->hp_drain_per_)/100;
+ if(sd->hp_drain_rate_ > 0 && hp < 1) hp = 1;
+ else if(sd->hp_drain_rate_ < 0 && hp > -1) hp = -1;
+ }
+ if(sd->sp_drain_rate && sd->sp_drain_per > 0 && wd.damage > 0 && rand()%100 < sd->sp_drain_rate) {
+ sp += (wd.damage * sd->sp_drain_per)/100;
+ if(sd->sp_drain_rate > 0 && sp < 1) sp = 1;
+ else if(sd->sp_drain_rate < 0 && sp > -1) sp = -1;
+ }
+ if(sd->sp_drain_rate_ && sd->sp_drain_per_ > 0 && wd.damage2 > 0 && rand()%100 < sd->sp_drain_rate_) {
+ sp += (wd.damage2 * sd->sp_drain_per_)/100;
+ if(sd->sp_drain_rate_ > 0 && sp < 1) sp = 1;
+ else if(sd->sp_drain_rate_ < 0 && sp > -1) sp = -1;
+ }
+ if(hp || sp) pc_heal(sd,hp,sp);
+ }
+ }
+
+ if(rdamage > 0)
+ battle_damage(target,src,rdamage,0);
+ if(t_sc_data && t_sc_data[SC_AUTOCOUNTER].timer != -1 && t_sc_data[SC_AUTOCOUNTER].val4 > 0) {
+ if(t_sc_data[SC_AUTOCOUNTER].val3 == src->id)
+ battle_weapon_attack(target,src,tick,0x8000|t_sc_data[SC_AUTOCOUNTER].val1);
+ skill_status_change_end(target,SC_AUTOCOUNTER,-1);
+ }
+ if(t_sc_data && t_sc_data[SC_BLADESTOP_WAIT].timer != -1){
+ int lv = t_sc_data[SC_BLADESTOP_WAIT].val1;
+ skill_status_change_end(target,SC_BLADESTOP_WAIT,-1);
+ skill_status_change_start(src,SC_BLADESTOP,lv,1,(int)src,(int)target,skill_get_time2(MO_BLADESTOP,lv),0);
+ skill_status_change_start(target,SC_BLADESTOP,lv,2,(int)target,(int)src,skill_get_time2(MO_BLADESTOP,lv),0);
+ }
+ if(t_sc_data && t_sc_data[SC_SPLASHER].timer!=-1) //殴ったので対象のベナムスプラッシャー状態を解除
+ skill_status_change_end(target,SC_SPLASHER,-1);
+
+ map_freeblock_unlock();
+ }
+ return wd.dmg_lv;
+}
+
+int battle_check_undead(int race,int element)
+{
+ if(battle_config.undead_detect_type == 0) {
+ if(element == 9)
+ return 1;
+ }
+ else if(battle_config.undead_detect_type == 1) {
+ if(race == 1)
+ return 1;
+ }
+ else {
+ if(element == 9 || race == 1)
+ return 1;
+ }
+ return 0;
+}
+
+/*==========================================
+ * 敵味方判定(1=肯定,0=否定,-1=エラー)
+ * flag&0xf0000 = 0x00000:敵じゃないか判定(ret:1=敵ではない)
+ * = 0x10000:パーティー判定(ret:1=パーティーメンバ)
+ * = 0x20000:全て(ret:1=敵味方両方)
+ * = 0x40000:敵か判定(ret:1=敵)
+ * = 0x50000:パーティーじゃないか判定(ret:1=パーティでない)
+ *------------------------------------------
+ */
+int battle_check_target( struct block_list *src, struct block_list *target,int flag)
+{
+ int s_p,s_g,t_p,t_g;
+ struct block_list *ss=src;
+
+ nullpo_retr(0, src);
+ nullpo_retr(0, target);
+
+ if( flag&0x40000 ){ // 反転フラグ
+ int ret=battle_check_target(src,target,flag&0x30000);
+ if(ret!=-1)
+ return !ret;
+ return -1;
+ }
+
+ if( flag&0x20000 ){
+ if( target->type==BL_MOB || target->type==BL_PC )
+ return 1;
+ else
+ return -1;
+ }
+
+ if(src->type == BL_SKILL && target->type == BL_SKILL) // 対象がスキルユニットなら無条件肯定
+ return -1;
+
+ if(target->type == BL_PC && ((struct map_session_data *)target)->invincible_timer != -1)
+ return -1;
+
+ if(target->type == BL_SKILL) {
+ switch(((struct skill_unit *)target)->group->unit_id){
+ case 0x8d:
+ case 0x8f:
+ case 0x98:
+ return 0;
+ break;
+ }
+ }
+
+ if(target->type == BL_PET)
+ return -1;
+
+ // スキルユニットの場合、親を求める
+ if( src->type==BL_SKILL) {
+ int inf2 = skill_get_inf2(((struct skill_unit *)src)->group->skill_id);
+ if( (ss=map_id2bl( ((struct skill_unit *)src)->group->src_id))==NULL )
+ return -1;
+ if(ss->prev == NULL)
+ return -1;
+ if(inf2&0x80 &&
+ (map[src->m].flag.pvp || pc_iskiller((struct map_session_data *)src, (struct map_session_data *)target)) && // [MouseJstr]
+ !(target->type == BL_PC && pc_isinvisible((struct map_session_data *)target)))
+ return 0;
+ if(ss == target) {
+ if(inf2&0x100)
+ return 0;
+ if(inf2&0x200)
+ return -1;
+ }
+ }
+ // Mobでmaster_idがあってspecial_mob_aiなら、召喚主を求める
+ if( src->type==BL_MOB ){
+ struct mob_data *md=(struct mob_data *)src;
+ if(md && md->master_id>0){
+ if(md->master_id==target->id) // 主なら肯定
+ return 1;
+ if(md->state.special_mob_ai){
+ if(target->type==BL_MOB){ //special_mob_aiで対象がMob
+ struct mob_data *tmd=(struct mob_data *)target;
+ if(tmd){
+ if(tmd->master_id != md->master_id) //召喚主が一緒でなければ否定
+ return 0;
+ else{ //召喚主が一緒なので肯定したいけど自爆は否定
+ if(md->state.special_mob_ai>2)
+ return 0;
+ else
+ return 1;
+ }
+ }
+ }
+ }
+ if((ss=map_id2bl(md->master_id))==NULL)
+ return -1;
+ }
+ }
+
+ if( src==target || ss==target ) // 同じなら肯定
+ return 1;
+
+ if(target->type == BL_PC && pc_isinvisible((struct map_session_data *)target))
+ return -1;
+
+ if( src->prev==NULL || // 死んでるならエラー
+ (src->type==BL_PC && pc_isdead((struct map_session_data *)src) ) )
+ return -1;
+
+ if( (ss->type == BL_PC && target->type==BL_MOB) ||
+ (ss->type == BL_MOB && target->type==BL_PC) )
+ return 0; // PCvsMOBなら否定
+
+ if(ss->type == BL_PET && target->type==BL_MOB)
+ return 0;
+
+ s_p=battle_get_party_id(ss);
+ s_g=battle_get_guild_id(ss);
+
+ t_p=battle_get_party_id(target);
+ t_g=battle_get_guild_id(target);
+
+ if(flag&0x10000) {
+ if(s_p && t_p && s_p == t_p) // 同じパーティなら肯定(味方)
+ return 1;
+ else // パーティ検索なら同じパーティじゃない時点で否定
+ return 0;
+ }
+
+ if(ss->type == BL_MOB && s_g > 0 && t_g > 0 && s_g == t_g ) // 同じギルド/mobクラスなら肯定(味方)
+ return 1;
+
+//printf("ss:%d src:%d target:%d flag:0x%x %d %d ",ss->id,src->id,target->id,flag,src->type,target->type);
+//printf("p:%d %d g:%d %d\n",s_p,t_p,s_g,t_g);
+
+ if( ss->type==BL_PC && target->type==BL_PC) { // 両方PVPモードなら否定(敵)
+ struct skill_unit *su=NULL;
+ if(src->type==BL_SKILL)
+ su=(struct skill_unit *)src;
+ if(map[ss->m].flag.pvp || pc_iskiller((struct map_session_data *)ss, (struct map_session_data*)target)) { // [MouseJstr]
+ if(su && su->group->target_flag==BCT_NOENEMY)
+ return 1;
+ else if(battle_config.pk_mode && (((struct map_session_data*)ss)->status.class==0 || ((struct map_session_data*)target)->status.class==0))
+ return 1; // prevent novice engagement in pk_mode [Valaris]
+ else if(map[ss->m].flag.pvp_noparty && s_p > 0 && t_p > 0 && s_p == t_p)
+ return 1;
+ else if(map[ss->m].flag.pvp_noguild && s_g > 0 && t_g > 0 && s_g == t_g)
+ return 1;
+ return 0;
+ }
+ if(map[src->m].flag.gvg) {
+ struct guild *g=NULL;
+ if(su && su->group->target_flag==BCT_NOENEMY)
+ return 1;
+ if( s_g > 0 && s_g == t_g)
+ return 1;
+ if(map[src->m].flag.gvg_noparty && s_p > 0 && t_p > 0 && s_p == t_p)
+ return 1;
+ if((g = guild_search(s_g))) {
+ int i;
+ for(i=0;i<MAX_GUILDALLIANCE;i++){
+ if(g->alliance[i].guild_id > 0 && g->alliance[i].guild_id == t_g) {
+ if(g->alliance[i].opposition)
+ return 0;//敵対ギルドなら無条件に敵
+ else
+ return 1;//同盟ギルドなら無条件に味方
+ }
+ }
+ }
+ return 0;
+ }
+ }
+
+ return 1; // 該当しないので無関係人物(まあ敵じゃないので味方)
+}
+/*==========================================
+ * 射程判定
+ *------------------------------------------
+ */
+int battle_check_range(struct block_list *src,struct block_list *bl,int range)
+{
+
+ int dx,dy;
+ struct walkpath_data wpd;
+ int arange;
+
+ nullpo_retr(0, src);
+ nullpo_retr(0, bl);
+
+ dx=abs(bl->x-src->x);
+ dy=abs(bl->y-src->y);
+ arange=((dx>dy)?dx:dy);
+
+ if(src->m != bl->m) // 違うマップ
+ return 0;
+
+ if( range>0 && range < arange ) // 遠すぎる
+ return 0;
+
+ if( arange<2 ) // 同じマスか隣接
+ return 1;
+
+// if(bl->type == BL_SKILL && ((struct skill_unit *)bl)->group->unit_id == 0x8d)
+// return 1;
+
+ // 障害物判定
+ wpd.path_len=0;
+ wpd.path_pos=0;
+ wpd.path_half=0;
+ if(path_search(&wpd,src->m,src->x,src->y,bl->x,bl->y,0x10001)!=-1)
+ return 1;
+
+ dx=(dx>0)?1:((dx<0)?-1:0);
+ dy=(dy>0)?1:((dy<0)?-1:0);
+ return (path_search(&wpd,src->m,src->x+dx,src->y+dy,
+ bl->x-dx,bl->y-dy,0x10001)!=-1)?1:0;
+}
+
+/*==========================================
+ * Return numerical value of a switch configuration (modified by [Yor])
+ * on/off, english, fran軋is, deutsch, espaol
+ *------------------------------------------
+ */
+int battle_config_switch(const char *str) {
+ if (strcmpi(str, "on") == 0 || strcmpi(str, "yes") == 0 || strcmpi(str, "oui") == 0 || strcmpi(str, "ja") == 0 || strcmpi(str, "si") == 0)
+ return 1;
+ if (strcmpi(str, "off") == 0 || strcmpi(str, "no") == 0 || strcmpi(str, "non") == 0 || strcmpi(str, "nein") == 0)
+ return 0;
+ return atoi(str);
+}
+
+static const struct {
+ char str[128];
+ int *val;
+} battle_data[] = {
+ { "warp_point_debug", &battle_config.warp_point_debug },
+ { "enemy_critical", &battle_config.enemy_critical },
+ { "enemy_critical_rate", &battle_config.enemy_critical_rate },
+ { "enemy_str", &battle_config.enemy_str },
+ { "enemy_perfect_flee", &battle_config.enemy_perfect_flee },
+ { "casting_rate", &battle_config.cast_rate },
+ { "delay_rate", &battle_config.delay_rate },
+ { "delay_dependon_dex", &battle_config.delay_dependon_dex },
+ { "skill_delay_attack_enable", &battle_config.sdelay_attack_enable },
+ { "left_cardfix_to_right", &battle_config.left_cardfix_to_right },
+ { "player_skill_add_range", &battle_config.pc_skill_add_range },
+ { "skill_out_range_consume", &battle_config.skill_out_range_consume },
+ { "monster_skill_add_range", &battle_config.mob_skill_add_range },
+ { "player_damage_delay", &battle_config.pc_damage_delay },
+ { "player_damage_delay_rate", &battle_config.pc_damage_delay_rate },
+ { "defunit_not_enemy", &battle_config.defnotenemy },
+ { "random_monster_checklv", &battle_config.random_monster_checklv },
+ { "attribute_recover", &battle_config.attr_recover },
+ { "flooritem_lifetime", &battle_config.flooritem_lifetime },
+ { "item_auto_get", &battle_config.item_auto_get },
+ { "item_first_get_time", &battle_config.item_first_get_time },
+ { "item_second_get_time", &battle_config.item_second_get_time },
+ { "item_third_get_time", &battle_config.item_third_get_time },
+ { "mvp_item_first_get_time", &battle_config.mvp_item_first_get_time },
+ { "mvp_item_second_get_time", &battle_config.mvp_item_second_get_time },
+ { "mvp_item_third_get_time", &battle_config.mvp_item_third_get_time },
+ { "item_rate", &battle_config.item_rate },
+ { "drop_rate0item", &battle_config.drop_rate0item },
+ { "base_exp_rate", &battle_config.base_exp_rate },
+ { "job_exp_rate", &battle_config.job_exp_rate },
+ { "pvp_exp", &battle_config.pvp_exp },
+ { "gtb_pvp_only", &battle_config.gtb_pvp_only },
+ { "guild_max_castles", &battle_config.guild_max_castles },
+ { "death_penalty_type", &battle_config.death_penalty_type },
+ { "death_penalty_base", &battle_config.death_penalty_base },
+ { "death_penalty_job", &battle_config.death_penalty_job },
+ { "zeny_penalty", &battle_config.zeny_penalty },
+ { "restart_hp_rate", &battle_config.restart_hp_rate },
+ { "restart_sp_rate", &battle_config.restart_sp_rate },
+ { "mvp_hp_rate", &battle_config.mvp_hp_rate },
+ { "mvp_item_rate", &battle_config.mvp_item_rate },
+ { "mvp_exp_rate", &battle_config.mvp_exp_rate },
+ { "monster_hp_rate", &battle_config.monster_hp_rate },
+ { "monster_max_aspd", &battle_config.monster_max_aspd },
+ { "atcommand_gm_only", &battle_config.atc_gmonly },
+ { "atcommand_spawn_quantity_limit", &battle_config.atc_spawn_quantity_limit },
+ { "gm_all_skill", &battle_config.gm_allskill },
+ { "gm_all_skill_add_abra", &battle_config.gm_allskill_addabra },
+ { "gm_all_equipment", &battle_config.gm_allequip },
+ { "gm_skill_unconditional", &battle_config.gm_skilluncond },
+ { "player_skillfree", &battle_config.skillfree },
+ { "player_skillup_limit", &battle_config.skillup_limit },
+ { "weapon_produce_rate", &battle_config.wp_rate },
+ { "potion_produce_rate", &battle_config.pp_rate },
+ { "monster_active_enable", &battle_config.monster_active_enable },
+ { "monster_damage_delay_rate", &battle_config.monster_damage_delay_rate},
+ { "monster_loot_type", &battle_config.monster_loot_type },
+ { "mob_skill_use", &battle_config.mob_skill_use },
+ { "mob_count_rate", &battle_config.mob_count_rate },
+ { "quest_skill_learn", &battle_config.quest_skill_learn },
+ { "quest_skill_reset", &battle_config.quest_skill_reset },
+ { "basic_skill_check", &battle_config.basic_skill_check },
+ { "guild_emperium_check", &battle_config.guild_emperium_check },
+ { "guild_exp_limit", &battle_config.guild_exp_limit },
+ { "player_invincible_time", &battle_config.pc_invincible_time },
+ { "pet_catch_rate", &battle_config.pet_catch_rate },
+ { "pet_rename", &battle_config.pet_rename },
+ { "pet_friendly_rate", &battle_config.pet_friendly_rate },
+ { "pet_hungry_delay_rate", &battle_config.pet_hungry_delay_rate },
+ { "pet_hungry_friendly_decrease", &battle_config.pet_hungry_friendly_decrease},
+ { "pet_str", &battle_config.pet_str },
+ { "pet_status_support", &battle_config.pet_status_support },
+ { "pet_attack_support", &battle_config.pet_attack_support },
+ { "pet_damage_support", &battle_config.pet_damage_support },
+ { "pet_support_rate", &battle_config.pet_support_rate },
+ { "pet_attack_exp_to_master", &battle_config.pet_attack_exp_to_master },
+ { "pet_attack_exp_rate", &battle_config.pet_attack_exp_rate },
+ { "skill_min_damage", &battle_config.skill_min_damage },
+ { "finger_offensive_type", &battle_config.finger_offensive_type },
+ { "heal_exp", &battle_config.heal_exp },
+ { "resurrection_exp", &battle_config.resurrection_exp },
+ { "shop_exp", &battle_config.shop_exp },
+ { "combo_delay_rate", &battle_config.combo_delay_rate },
+ { "item_check", &battle_config.item_check },
+ { "wedding_modifydisplay", &battle_config.wedding_modifydisplay },
+ { "natural_healhp_interval", &battle_config.natural_healhp_interval },
+ { "natural_healsp_interval", &battle_config.natural_healsp_interval },
+ { "natural_heal_skill_interval", &battle_config.natural_heal_skill_interval},
+ { "natural_heal_weight_rate", &battle_config.natural_heal_weight_rate },
+ { "item_name_override_grffile", &battle_config.item_name_override_grffile},
+ { "arrow_decrement", &battle_config.arrow_decrement },
+ { "max_aspd", &battle_config.max_aspd },
+ { "max_hp", &battle_config.max_hp },
+ { "max_sp", &battle_config.max_sp },
+ { "max_lv", &battle_config.max_lv },
+ { "max_parameter", &battle_config.max_parameter },
+ { "max_cart_weight", &battle_config.max_cart_weight },
+ { "player_skill_log", &battle_config.pc_skill_log },
+ { "monster_skill_log", &battle_config.mob_skill_log },
+ { "battle_log", &battle_config.battle_log },
+ { "save_log", &battle_config.save_log },
+ { "error_log", &battle_config.error_log },
+ { "etc_log", &battle_config.etc_log },
+ { "save_clothcolor", &battle_config.save_clothcolor },
+ { "undead_detect_type", &battle_config.undead_detect_type },
+ { "player_auto_counter_type", &battle_config.pc_auto_counter_type },
+ { "monster_auto_counter_type", &battle_config.monster_auto_counter_type},
+ { "agi_penaly_type", &battle_config.agi_penaly_type },
+ { "agi_penaly_count", &battle_config.agi_penaly_count },
+ { "agi_penaly_num", &battle_config.agi_penaly_num },
+ { "agi_penaly_count_lv", &battle_config.agi_penaly_count_lv },
+ { "vit_penaly_type", &battle_config.vit_penaly_type },
+ { "vit_penaly_count", &battle_config.vit_penaly_count },
+ { "vit_penaly_num", &battle_config.vit_penaly_num },
+ { "vit_penaly_count_lv", &battle_config.vit_penaly_count_lv },
+ { "player_defense_type", &battle_config.player_defense_type },
+ { "monster_defense_type", &battle_config.monster_defense_type },
+ { "pet_defense_type", &battle_config.pet_defense_type },
+ { "magic_defense_type", &battle_config.magic_defense_type },
+ { "player_skill_reiteration", &battle_config.pc_skill_reiteration },
+ { "monster_skill_reiteration", &battle_config.monster_skill_reiteration},
+ { "player_skill_nofootset", &battle_config.pc_skill_nofootset },
+ { "monster_skill_nofootset", &battle_config.monster_skill_nofootset },
+ { "player_cloak_check_type", &battle_config.pc_cloak_check_type },
+ { "monster_cloak_check_type", &battle_config.monster_cloak_check_type },
+ { "gvg_short_attack_damage_rate", &battle_config.gvg_short_damage_rate },
+ { "gvg_long_attack_damage_rate", &battle_config.gvg_long_damage_rate },
+ { "gvg_magic_attack_damage_rate", &battle_config.gvg_magic_damage_rate },
+ { "gvg_misc_attack_damage_rate", &battle_config.gvg_misc_damage_rate },
+ { "gvg_eliminate_time", &battle_config.gvg_eliminate_time },
+ { "mob_changetarget_byskill", &battle_config.mob_changetarget_byskill},
+ { "player_attack_direction_change", &battle_config.pc_attack_direction_change },
+ { "monster_attack_direction_change", &battle_config.monster_attack_direction_change },
+ { "player_land_skill_limit", &battle_config.pc_land_skill_limit },
+ { "monster_land_skill_limit", &battle_config.monster_land_skill_limit},
+ { "party_skill_penaly", &battle_config.party_skill_penaly },
+ { "monster_class_change_full_recover", &battle_config.monster_class_change_full_recover },
+ { "produce_item_name_input", &battle_config.produce_item_name_input },
+ { "produce_potion_name_input", &battle_config.produce_potion_name_input},
+ { "making_arrow_name_input", &battle_config.making_arrow_name_input },
+ { "holywater_name_input", &battle_config.holywater_name_input },
+ { "display_delay_skill_fail", &battle_config.display_delay_skill_fail },
+ { "chat_warpportal", &battle_config.chat_warpportal },
+ { "mob_warpportal", &battle_config.mob_warpportal },
+ { "dead_branch_active", &battle_config.dead_branch_active },
+ { "vending_max_value", &battle_config.vending_max_value },
+ { "show_steal_in_same_party", &battle_config.show_steal_in_same_party },
+ { "enable_upper_class", &battle_config.enable_upper_class },
+ { "pet_attack_attr_none", &battle_config.pet_attack_attr_none },
+ { "mob_attack_attr_none", &battle_config.mob_attack_attr_none },
+ { "mob_ghostring_fix", &battle_config.mob_ghostring_fix },
+ { "pc_attack_attr_none", &battle_config.pc_attack_attr_none },
+ { "gx_allhit", &battle_config.gx_allhit },
+ { "gx_cardfix", &battle_config.gx_cardfix },
+ { "gx_dupele", &battle_config.gx_dupele },
+ { "gx_disptype", &battle_config.gx_disptype },
+ { "player_skill_partner_check", &battle_config.player_skill_partner_check},
+ { "hide_GM_session", &battle_config.hide_GM_session },
+ { "unit_movement_type", &battle_config.unit_movement_type },
+ { "invite_request_check", &battle_config.invite_request_check },
+ { "skill_removetrap_type", &battle_config.skill_removetrap_type },
+ { "disp_experience", &battle_config.disp_experience },
+ { "castle_defense_rate", &battle_config.castle_defense_rate },
+ { "riding_weight", &battle_config.riding_weight },
+ { "item_rate_common", &battle_config.item_rate_common }, // Added by RoVeRT
+ { "item_rate_equip", &battle_config.item_rate_equip },
+ { "item_rate_card", &battle_config.item_rate_card }, // End Addition
+ { "item_rate_heal", &battle_config.item_rate_heal }, // Added by Valaris
+ { "item_rate_use", &battle_config.item_rate_use }, // End
+ { "item_drop_common_min", &battle_config.item_drop_common_min }, // Added by TyrNemesis^
+ { "item_drop_common_max", &battle_config.item_drop_common_max },
+ { "item_drop_equip_min", &battle_config.item_drop_equip_min },
+ { "item_drop_equip_max", &battle_config.item_drop_equip_max },
+ { "item_drop_card_min", &battle_config.item_drop_card_min },
+ { "item_drop_card_max", &battle_config.item_drop_card_max },
+ { "item_drop_mvp_min", &battle_config.item_drop_mvp_min },
+ { "item_drop_mvp_max", &battle_config.item_drop_mvp_max }, // End Addition
+ { "prevent_logout", &battle_config.prevent_logout }, // Added by RoVeRT
+ { "alchemist_summon_reward", &battle_config.alchemist_summon_reward }, // [Valaris]
+ { "maximum_level", &battle_config.maximum_level }, // [Valaris]
+ { "drops_by_luk", &battle_config.drops_by_luk }, // [Valaris]
+ { "monsters_ignore_gm", &battle_config.monsters_ignore_gm }, // [Valaris]
+ { "equipment_breaking", &battle_config.equipment_breaking }, // [Valaris]
+ { "equipment_break_rate", &battle_config.equipment_break_rate }, // [Valaris]
+ { "pk_mode", &battle_config.pk_mode }, // [Valaris]
+ { "pet_equip_required", &battle_config.pet_equip_required }, // [Valaris]
+ { "multi_level_up", &battle_config.multi_level_up }, // [Valaris]
+ { "backstab_bow_penalty", &battle_config.backstab_bow_penalty },
+ { "night_at_start", &battle_config.night_at_start }, // added by [Yor]
+ { "day_duration", &battle_config.day_duration }, // added by [Yor]
+ { "night_duration", &battle_config.night_duration }, // added by [Yor]
+ { "show_mob_hp", &battle_config.show_mob_hp }, // [Valaris]
+ { "ban_spoof_namer", &battle_config.ban_spoof_namer }, // added by [Yor]
+ { "hack_info_GM_level", &battle_config.hack_info_GM_level }, // added by [Yor]
+ { "any_warp_GM_min_level", &battle_config.any_warp_GM_min_level }, // added by [Yor]
+ { "packet_ver_flag", &battle_config.packet_ver_flag }, // added by [Yor]
+ { "min_hair_style", &battle_config.min_hair_style }, // added by [MouseJstr]
+ { "max_hair_style", &battle_config.max_hair_style }, // added by [MouseJstr]
+ { "min_hair_color", &battle_config.min_hair_color }, // added by [MouseJstr]
+ { "max_hair_color", &battle_config.max_hair_color }, // added by [MouseJstr]
+ { "min_cloth_color", &battle_config.min_cloth_color }, // added by [MouseJstr]
+ { "max_cloth_color", &battle_config.max_cloth_color }, // added by [MouseJstr]
+ { "castrate_dex_scale", &battle_config.castrate_dex_scale }, // added by [MouseJstr]
+ { "area_size", &battle_config.area_size }, // added by [MouseJstr]
+ { "muting_players", &battle_config.muting_players}, // added by [Apple]
+//SQL-only options start
+#ifndef TXT_ONLY
+ { "mail_system", &battle_config.mail_system }, // added by [Valaris]
+//SQL-only options end
+#endif
+};
+
+int battle_set_value(char *w1, char *w2) {
+ int i;
+ for(i = 0; i < sizeof(battle_data) / (sizeof(battle_data[0])); i++)
+ if (strcmpi(w1, battle_data[i].str) == 0) {
+ *battle_data[i].val = battle_config_switch(w2);
+ return 1;
+ }
+ return 0;
+}
+
+void battle_set_defaults() {
+ battle_config.warp_point_debug=0;
+ battle_config.enemy_critical=0;
+ battle_config.enemy_critical_rate=100;
+ battle_config.enemy_str=1;
+ battle_config.enemy_perfect_flee=0;
+ battle_config.cast_rate=100;
+ battle_config.delay_rate=100;
+ battle_config.delay_dependon_dex=0;
+ battle_config.sdelay_attack_enable=0;
+ battle_config.left_cardfix_to_right=0;
+ battle_config.pc_skill_add_range=0;
+ battle_config.skill_out_range_consume=1;
+ battle_config.mob_skill_add_range=0;
+ battle_config.pc_damage_delay=1;
+ battle_config.pc_damage_delay_rate=100;
+ battle_config.defnotenemy=1;
+ battle_config.random_monster_checklv=1;
+ battle_config.attr_recover=1;
+ battle_config.flooritem_lifetime=LIFETIME_FLOORITEM*1000;
+ battle_config.item_auto_get=0;
+ battle_config.item_first_get_time=3000;
+ battle_config.item_second_get_time=1000;
+ battle_config.item_third_get_time=1000;
+ battle_config.mvp_item_first_get_time=10000;
+ battle_config.mvp_item_second_get_time=10000;
+ battle_config.mvp_item_third_get_time=2000;
+
+ battle_config.drop_rate0item=0;
+ battle_config.base_exp_rate=100;
+ battle_config.job_exp_rate=100;
+ battle_config.pvp_exp=1;
+ battle_config.gtb_pvp_only=0;
+ battle_config.death_penalty_type=0;
+ battle_config.death_penalty_base=0;
+ battle_config.death_penalty_job=0;
+ battle_config.zeny_penalty=0;
+ battle_config.restart_hp_rate=0;
+ battle_config.restart_sp_rate=0;
+ battle_config.mvp_item_rate=100;
+ battle_config.mvp_exp_rate=100;
+ battle_config.mvp_hp_rate=100;
+ battle_config.monster_hp_rate=100;
+ battle_config.monster_max_aspd=199;
+ battle_config.atc_gmonly=0;
+ battle_config.gm_allskill=0;
+ battle_config.gm_allequip=0;
+ battle_config.gm_skilluncond=0;
+ battle_config.guild_max_castles=0;
+ battle_config.skillfree = 0;
+ battle_config.skillup_limit = 0;
+ battle_config.wp_rate=100;
+ battle_config.pp_rate=100;
+ battle_config.monster_active_enable=1;
+ battle_config.monster_damage_delay_rate=100;
+ battle_config.monster_loot_type=0;
+ battle_config.mob_skill_use=1;
+ battle_config.mob_count_rate=100;
+ battle_config.quest_skill_learn=0;
+ battle_config.quest_skill_reset=1;
+ battle_config.basic_skill_check=1;
+ battle_config.guild_emperium_check=1;
+ battle_config.guild_exp_limit=50;
+ battle_config.pc_invincible_time = 5000;
+ battle_config.pet_catch_rate=100;
+ battle_config.pet_rename=0;
+ battle_config.pet_friendly_rate=100;
+ battle_config.pet_hungry_delay_rate=100;
+ battle_config.pet_hungry_friendly_decrease=5;
+ battle_config.pet_str=1;
+ battle_config.pet_status_support=0;
+ battle_config.pet_attack_support=0;
+ battle_config.pet_damage_support=0;
+ battle_config.pet_support_rate=100;
+ battle_config.pet_attack_exp_to_master=0;
+ battle_config.pet_attack_exp_rate=100;
+ battle_config.skill_min_damage=0;
+ battle_config.finger_offensive_type=0;
+ battle_config.heal_exp=0;
+ battle_config.resurrection_exp=0;
+ battle_config.shop_exp=0;
+ battle_config.combo_delay_rate=100;
+ battle_config.item_check=1;
+ battle_config.wedding_modifydisplay=0;
+ battle_config.natural_healhp_interval=6000;
+ battle_config.natural_healsp_interval=8000;
+ battle_config.natural_heal_skill_interval=10000;
+ battle_config.natural_heal_weight_rate=50;
+ battle_config.item_name_override_grffile=1;
+ battle_config.arrow_decrement=1;
+ battle_config.max_aspd = 199;
+ battle_config.max_hp = 32500;
+ battle_config.max_sp = 32500;
+ battle_config.max_lv = 99; // [MouseJstr]
+ battle_config.max_parameter = 99;
+ battle_config.max_cart_weight = 8000;
+ battle_config.pc_skill_log = 0;
+ battle_config.mob_skill_log = 0;
+ battle_config.battle_log = 0;
+ battle_config.save_log = 0;
+ battle_config.error_log = 1;
+ battle_config.etc_log = 1;
+ battle_config.save_clothcolor = 0;
+ battle_config.undead_detect_type = 0;
+ battle_config.pc_auto_counter_type = 1;
+ battle_config.monster_auto_counter_type = 1;
+ battle_config.agi_penaly_type = 0;
+ battle_config.agi_penaly_count = 3;
+ battle_config.agi_penaly_num = 0;
+ battle_config.agi_penaly_count_lv = ATK_FLEE;
+ battle_config.vit_penaly_type = 0;
+ battle_config.vit_penaly_count = 3;
+ battle_config.vit_penaly_num = 0;
+ battle_config.vit_penaly_count_lv = ATK_DEF;
+ battle_config.player_defense_type = 0;
+ battle_config.monster_defense_type = 0;
+ battle_config.pet_defense_type = 0;
+ battle_config.magic_defense_type = 0;
+ battle_config.pc_skill_reiteration = 0;
+ battle_config.monster_skill_reiteration = 0;
+ battle_config.pc_skill_nofootset = 0;
+ battle_config.monster_skill_nofootset = 0;
+ battle_config.pc_cloak_check_type = 0;
+ battle_config.monster_cloak_check_type = 0;
+ battle_config.gvg_short_damage_rate = 100;
+ battle_config.gvg_long_damage_rate = 100;
+ battle_config.gvg_magic_damage_rate = 100;
+ battle_config.gvg_misc_damage_rate = 100;
+ battle_config.gvg_eliminate_time = 7000;
+ battle_config.mob_changetarget_byskill = 0;
+ battle_config.pc_attack_direction_change = 1;
+ battle_config.monster_attack_direction_change = 1;
+ battle_config.pc_undead_nofreeze = 0;
+ battle_config.pc_land_skill_limit = 1;
+ battle_config.monster_land_skill_limit = 1;
+ battle_config.party_skill_penaly = 1;
+ battle_config.monster_class_change_full_recover = 0;
+ battle_config.produce_item_name_input = 1;
+ battle_config.produce_potion_name_input = 1;
+ battle_config.making_arrow_name_input = 1;
+ battle_config.holywater_name_input = 1;
+ battle_config.display_delay_skill_fail = 1;
+ battle_config.chat_warpportal = 0;
+ battle_config.mob_warpportal = 0;
+ battle_config.dead_branch_active = 0;
+ battle_config.vending_max_value = 10000000;
+ battle_config.show_steal_in_same_party = 0;
+ battle_config.enable_upper_class = 0;
+ battle_config.pet_attack_attr_none = 0;
+ battle_config.pc_attack_attr_none = 0;
+ battle_config.mob_attack_attr_none = 1;
+ battle_config.mob_ghostring_fix = 0;
+ battle_config.gx_allhit = 0;
+ battle_config.gx_cardfix = 0;
+ battle_config.gx_dupele = 1;
+ battle_config.gx_disptype = 1;
+ battle_config.player_skill_partner_check = 1;
+ battle_config.hide_GM_session = 0;
+ battle_config.unit_movement_type = 0;
+ battle_config.invite_request_check = 1;
+ battle_config.skill_removetrap_type = 0;
+ battle_config.disp_experience = 0;
+ battle_config.item_rate_common = 100;
+ battle_config.item_rate_equip = 100;
+ battle_config.item_rate_card = 100;
+ battle_config.item_rate_heal = 100; // Added by Valaris
+ battle_config.item_rate_use = 100; // End
+ battle_config.item_drop_common_min=1; // Added by TyrNemesis^
+ battle_config.item_drop_common_max=10000;
+ battle_config.item_drop_equip_min=1;
+ battle_config.item_drop_equip_max=10000;
+ battle_config.item_drop_card_min=1;
+ battle_config.item_drop_card_max=10000;
+ battle_config.item_drop_mvp_min=1;
+ battle_config.item_drop_mvp_max=10000; // End Addition
+ battle_config.item_drop_heal_min=1; // Added by Valaris
+ battle_config.item_drop_heal_max=10000;
+ battle_config.item_drop_use_min=1;
+ battle_config.item_drop_use_max=10000; // End
+ battle_config.prevent_logout = 1; // Added by RoVeRT
+ battle_config.maximum_level = 255; // Added by Valaris
+ battle_config.drops_by_luk = 0; // [Valaris]
+ battle_config.equipment_breaking = 0; // [Valaris]
+ battle_config.equipment_break_rate = 100; // [Valaris]
+ battle_config.pk_mode = 0; // [Valaris]
+ battle_config.pet_equip_required = 0; // [Valaris]
+ battle_config.multi_level_up = 0; // [Valaris]
+ battle_config.backstab_bow_penalty = 0; // Akaru
+ battle_config.night_at_start = 0; // added by [Yor]
+ battle_config.day_duration = 2*60*60*1000; // added by [Yor] (2 hours)
+ battle_config.night_duration = 30*60*1000; // added by [Yor] (30 minutes)
+ battle_config.show_mob_hp = 0; // [Valaris]
+ battle_config.ban_spoof_namer = 5; // added by [Yor] (default: 5 minutes)
+ battle_config.hack_info_GM_level = 60; // added by [Yor] (default: 60, GM level)
+ battle_config.any_warp_GM_min_level = 20; // added by [Yor]
+ battle_config.packet_ver_flag = 63; // added by [Yor]
+ battle_config.min_hair_style = 0;
+ battle_config.max_hair_style = 20;
+ battle_config.min_hair_color = 0;
+ battle_config.max_hair_color = 9;
+ battle_config.min_cloth_color = 0;
+ battle_config.max_cloth_color = 4;
+
+ battle_config.castrate_dex_scale = 150;
+
+ battle_config.area_size = 14;
+
+//SQL-only options start
+#ifndef TXT_ONLY
+ battle_config.mail_system = 0;
+//SQL-only options end
+#endif
+}
+
+void battle_validate_conf() {
+ if(battle_config.flooritem_lifetime < 1000)
+ battle_config.flooritem_lifetime = LIFETIME_FLOORITEM*1000;
+ if(battle_config.restart_hp_rate < 0)
+ battle_config.restart_hp_rate = 0;
+ else if(battle_config.restart_hp_rate > 100)
+ battle_config.restart_hp_rate = 100;
+ if(battle_config.restart_sp_rate < 0)
+ battle_config.restart_sp_rate = 0;
+ else if(battle_config.restart_sp_rate > 100)
+ battle_config.restart_sp_rate = 100;
+ if(battle_config.natural_healhp_interval < NATURAL_HEAL_INTERVAL)
+ battle_config.natural_healhp_interval=NATURAL_HEAL_INTERVAL;
+ if(battle_config.natural_healsp_interval < NATURAL_HEAL_INTERVAL)
+ battle_config.natural_healsp_interval=NATURAL_HEAL_INTERVAL;
+ if(battle_config.natural_heal_skill_interval < NATURAL_HEAL_INTERVAL)
+ battle_config.natural_heal_skill_interval=NATURAL_HEAL_INTERVAL;
+ if(battle_config.natural_heal_weight_rate < 50)
+ battle_config.natural_heal_weight_rate = 50;
+ if(battle_config.natural_heal_weight_rate > 101)
+ battle_config.natural_heal_weight_rate = 101;
+ battle_config.monster_max_aspd = 2000 - battle_config.monster_max_aspd*10;
+ if(battle_config.monster_max_aspd < 10)
+ battle_config.monster_max_aspd = 10;
+ if(battle_config.monster_max_aspd > 1000)
+ battle_config.monster_max_aspd = 1000;
+ battle_config.max_aspd = 2000 - battle_config.max_aspd*10;
+ if(battle_config.max_aspd < 10)
+ battle_config.max_aspd = 10;
+ if(battle_config.max_aspd > 1000)
+ battle_config.max_aspd = 1000;
+ if(battle_config.max_hp > 1000000)
+ battle_config.max_hp = 1000000;
+ if(battle_config.max_hp < 100)
+ battle_config.max_hp = 100;
+ if(battle_config.max_sp > 1000000)
+ battle_config.max_sp = 1000000;
+ if(battle_config.max_sp < 100)
+ battle_config.max_sp = 100;
+ if(battle_config.max_parameter < 10)
+ battle_config.max_parameter = 10;
+ if(battle_config.max_parameter > 10000)
+ battle_config.max_parameter = 10000;
+ if(battle_config.max_cart_weight > 1000000)
+ battle_config.max_cart_weight = 1000000;
+ if(battle_config.max_cart_weight < 100)
+ battle_config.max_cart_weight = 100;
+ battle_config.max_cart_weight *= 10;
+
+ if(battle_config.agi_penaly_count < 2)
+ battle_config.agi_penaly_count = 2;
+ if(battle_config.vit_penaly_count < 2)
+ battle_config.vit_penaly_count = 2;
+
+ if(battle_config.guild_exp_limit > 99)
+ battle_config.guild_exp_limit = 99;
+ if(battle_config.guild_exp_limit < 0)
+ battle_config.guild_exp_limit = 0;
+
+ if(battle_config.castle_defense_rate < 0)
+ battle_config.castle_defense_rate = 0;
+ if(battle_config.castle_defense_rate > 100)
+ battle_config.castle_defense_rate = 100;
+ if(battle_config.item_drop_common_min < 1) // Added by TyrNemesis^
+ battle_config.item_drop_common_min = 1;
+ if(battle_config.item_drop_common_max > 10000)
+ battle_config.item_drop_common_max = 10000;
+ if(battle_config.item_drop_equip_min < 1)
+ battle_config.item_drop_equip_min = 1;
+ if(battle_config.item_drop_equip_max > 10000)
+ battle_config.item_drop_equip_max = 10000;
+ if(battle_config.item_drop_card_min < 1)
+ battle_config.item_drop_card_min = 1;
+ if(battle_config.item_drop_card_max > 10000)
+ battle_config.item_drop_card_max = 10000;
+ if(battle_config.item_drop_mvp_min < 1)
+ battle_config.item_drop_mvp_min = 1;
+ if(battle_config.item_drop_mvp_max > 10000)
+ battle_config.item_drop_mvp_max = 10000; // End Addition
+
+ if (battle_config.night_at_start < 0) // added by [Yor]
+ battle_config.night_at_start = 0;
+ else if (battle_config.night_at_start > 1) // added by [Yor]
+ battle_config.night_at_start = 1;
+ if (battle_config.day_duration < 0) // added by [Yor]
+ battle_config.day_duration = 0;
+ if (battle_config.night_duration < 0) // added by [Yor]
+ battle_config.night_duration = 0;
+
+ if (battle_config.ban_spoof_namer < 0) // added by [Yor]
+ battle_config.ban_spoof_namer = 0;
+ else if (battle_config.ban_spoof_namer > 32767)
+ battle_config.ban_spoof_namer = 32767;
+
+ if (battle_config.hack_info_GM_level < 0) // added by [Yor]
+ battle_config.hack_info_GM_level = 0;
+ else if (battle_config.hack_info_GM_level > 100)
+ battle_config.hack_info_GM_level = 100;
+
+ if (battle_config.any_warp_GM_min_level < 0) // added by [Yor]
+ battle_config.any_warp_GM_min_level = 0;
+ else if (battle_config.any_warp_GM_min_level > 100)
+ battle_config.any_warp_GM_min_level = 100;
+
+ // at least 1 client must be accepted
+ if ((battle_config.packet_ver_flag & 63) == 0) // added by [Yor]
+ battle_config.packet_ver_flag = 63; // accept all clients
+}
+
+/*==========================================
+ * 設定ファイルを読み込む
+ *------------------------------------------
+ */
+int battle_config_read(const char *cfgName)
+{
+ char line[1024], w1[1024], w2[1024];
+ FILE *fp;
+ static int count = 0;
+
+ if ((count++) == 0)
+ battle_set_defaults();
+
+ fp = fopen(cfgName,"r");
+ if (fp == NULL) {
+ printf("file not found: %s\n", cfgName);
+ return 1;
+ }
+ while(fgets(line,1020,fp)){
+ if (line[0] == '/' && line[1] == '/')
+ continue;
+ if (sscanf(line, "%[^:]:%s", w1, w2) != 2)
+ continue;
+ battle_set_value(w1, w2);
+ if (strcmpi(w1, "import") == 0)
+ battle_config_read(w2);
+ }
+ fclose(fp);
+
+ if (--count == 0) {
+ battle_validate_conf();
+ add_timer_func_list(battle_delay_damage_sub, "battle_delay_damage_sub");
+ }
+
+ return 0;
+}
diff --git a/src/map/battle.h b/src/map/battle.h
new file mode 100644
index 000000000..d4f680509
--- /dev/null
+++ b/src/map/battle.h
@@ -0,0 +1,345 @@
+// $Id: battle.h,v 1.6 2004/09/29 21:08:17 Akitasha Exp $
+#ifndef _BATTLE_H_
+#define _BATTLE_H_
+
+// ダメージ
+struct Damage {
+ int damage,damage2;
+ int type,div_;
+ int amotion,dmotion;
+ int blewcount;
+ int flag;
+ int dmg_lv; //囲まれ減算計算用 0:スキル攻撃 ATK_LUCKY,ATK_FLEE,ATK_DEF
+};
+
+// 属性表(読み込みはpc.c、battle_attr_fixで使用)
+extern int attr_fix_table[4][10][10];
+
+struct map_session_data;
+struct mob_data;
+struct block_list;
+
+// ダメージ計算
+
+struct Damage battle_calc_attack( int attack_type,
+ struct block_list *bl,struct block_list *target,int skill_num,int skill_lv,int flag);
+struct Damage battle_calc_weapon_attack(
+ struct block_list *bl,struct block_list *target,int skill_num,int skill_lv,int flag);
+struct Damage battle_calc_magic_attack(
+ struct block_list *bl,struct block_list *target,int skill_num,int skill_lv,int flag);
+struct Damage battle_calc_misc_attack(
+ struct block_list *bl,struct block_list *target,int skill_num,int skill_lv,int flag);
+
+// 属性修正計算
+int battle_attr_fix(int damage,int atk_elem,int def_elem);
+
+// ダメージ最終計算
+int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,int div_,int skill_num,int skill_lv,int flag);
+enum { // 最終計算のフラグ
+ BF_WEAPON = 0x0001,
+ BF_MAGIC = 0x0002,
+ BF_MISC = 0x0004,
+ BF_SHORT = 0x0010,
+ BF_LONG = 0x0040,
+ BF_SKILL = 0x0100,
+ BF_NORMAL = 0x0200,
+ BF_WEAPONMASK=0x000f,
+ BF_RANGEMASK= 0x00f0,
+ BF_SKILLMASK= 0x0f00,
+};
+
+// 実際にHPを増減
+int battle_delay_damage(unsigned int tick,struct block_list *src,struct block_list *target,int damage,int flag);
+int battle_damage(struct block_list *bl,struct block_list *target,int damage,int flag);
+int battle_heal(struct block_list *bl,struct block_list *target,int hp,int sp,int flag);
+
+// 攻撃や移動を止める
+int battle_stopattack(struct block_list *bl);
+int battle_stopwalking(struct block_list *bl,int type);
+
+// 通常攻撃処理まとめ
+int battle_weapon_attack( struct block_list *bl,struct block_list *target,
+ unsigned int tick,int flag);
+
+// 各種パラメータを得る
+int battle_counttargeted(struct block_list *bl,struct block_list *src,int target_lv);
+int battle_get_class(struct block_list *bl);
+int battle_get_dir(struct block_list *bl);
+int battle_get_lv(struct block_list *bl);
+int battle_get_range(struct block_list *bl);
+int battle_get_hp(struct block_list *bl);
+int battle_get_max_hp(struct block_list *bl);
+int battle_get_str(struct block_list *bl);
+int battle_get_agi(struct block_list *bl);
+int battle_get_vit(struct block_list *bl);
+int battle_get_int(struct block_list *bl);
+int battle_get_dex(struct block_list *bl);
+int battle_get_luk(struct block_list *bl);
+int battle_get_hit(struct block_list *bl);
+int battle_get_flee(struct block_list *bl);
+int battle_get_def(struct block_list *bl);
+int battle_get_mdef(struct block_list *bl);
+int battle_get_flee2(struct block_list *bl);
+int battle_get_def2(struct block_list *bl);
+int battle_get_mdef2(struct block_list *bl);
+int battle_get_baseatk(struct block_list *bl);
+int battle_get_atk(struct block_list *bl);
+int battle_get_atk2(struct block_list *bl);
+int battle_get_speed(struct block_list *bl);
+int battle_get_adelay(struct block_list *bl);
+int battle_get_amotion(struct block_list *bl);
+int battle_get_dmotion(struct block_list *bl);
+int battle_get_element(struct block_list *bl);
+int battle_get_attack_element(struct block_list *bl);
+int battle_get_attack_element2(struct block_list *bl); //左手武器属性取得
+#define battle_get_elem_type(bl) (battle_get_element(bl)%10)
+#define battle_get_elem_level(bl) (battle_get_element(bl)/10/2)
+int battle_get_party_id(struct block_list *bl);
+int battle_get_guild_id(struct block_list *bl);
+int battle_get_race(struct block_list *bl);
+int battle_get_size(struct block_list *bl);
+int battle_get_mode(struct block_list *bl);
+int battle_get_mexp(struct block_list *bl);
+
+struct status_change *battle_get_sc_data(struct block_list *bl);
+short *battle_get_sc_count(struct block_list *bl);
+short *battle_get_opt1(struct block_list *bl);
+short *battle_get_opt2(struct block_list *bl);
+short *battle_get_opt3(struct block_list *bl);
+short *battle_get_option(struct block_list *bl);
+
+enum {
+ BCT_NOENEMY =0x00000,
+ BCT_PARTY =0x10000,
+ BCT_ENEMY =0x40000,
+ BCT_NOPARTY =0x50000,
+ BCT_ALL =0x20000,
+ BCT_NOONE =0x60000,
+};
+
+int battle_check_undead(int race,int element);
+int battle_check_target( struct block_list *src, struct block_list *target,int flag);
+int battle_check_range(struct block_list *src,struct block_list *bl,int range);
+
+
+// 設定
+
+int battle_config_switch(const char *str); // [Valaris]
+
+extern struct Battle_Config {
+ int warp_point_debug;
+ int enemy_critical;
+ int enemy_critical_rate;
+ int enemy_str;
+ int enemy_perfect_flee;
+ int cast_rate,delay_rate,delay_dependon_dex;
+ int sdelay_attack_enable;
+ int left_cardfix_to_right;
+ int pc_skill_add_range;
+ int skill_out_range_consume;
+ int mob_skill_add_range;
+ int pc_damage_delay;
+ int pc_damage_delay_rate;
+ int defnotenemy;
+ int random_monster_checklv;
+ int attr_recover;
+ int flooritem_lifetime;
+ int item_auto_get;
+ int item_first_get_time;
+ int item_second_get_time;
+ int item_third_get_time;
+ int mvp_item_first_get_time;
+ int mvp_item_second_get_time;
+ int mvp_item_third_get_time;
+ int item_rate,base_exp_rate,job_exp_rate; // removed item rate, depreciated
+ int drop_rate0item;
+ int death_penalty_type;
+ int death_penalty_base,death_penalty_job;
+ int pvp_exp; // [MouseJstr]
+ int gtb_pvp_only; // [MouseJstr]
+ int zeny_penalty;
+ int restart_hp_rate;
+ int restart_sp_rate;
+ int mvp_item_rate,mvp_exp_rate;
+ int mvp_hp_rate;
+ int monster_hp_rate;
+ int monster_max_aspd;
+ int atc_gmonly;
+ int atc_spawn_quantity_limit;
+ int gm_allskill;
+ int gm_allskill_addabra;
+ int gm_allequip;
+ int gm_skilluncond;
+ int skillfree;
+ int skillup_limit;
+ int wp_rate;
+ int pp_rate;
+ int monster_active_enable;
+ int monster_damage_delay_rate;
+ int monster_loot_type;
+ int mob_skill_use;
+ int mob_count_rate;
+ int quest_skill_learn;
+ int quest_skill_reset;
+ int basic_skill_check;
+ int guild_emperium_check;
+ int guild_exp_limit;
+ int guild_max_castles;
+ int pc_invincible_time;
+ int pet_catch_rate;
+ int pet_rename;
+ int pet_friendly_rate;
+ int pet_hungry_delay_rate;
+ int pet_hungry_friendly_decrease;
+ int pet_str;
+ int pet_status_support;
+ int pet_attack_support;
+ int pet_damage_support;
+ int pet_support_rate;
+ int pet_attack_exp_to_master;
+ int pet_attack_exp_rate;
+ int skill_min_damage;
+ int finger_offensive_type;
+ int heal_exp;
+ int resurrection_exp;
+ int shop_exp;
+ int combo_delay_rate;
+ int item_check;
+ int wedding_modifydisplay;
+ int natural_healhp_interval;
+ int natural_healsp_interval;
+ int natural_heal_skill_interval;
+ int natural_heal_weight_rate;
+ int item_name_override_grffile;
+ int arrow_decrement;
+ int max_aspd;
+ int max_hp;
+ int max_sp;
+ int max_lv;
+ int max_parameter;
+ int max_cart_weight;
+ int pc_skill_log;
+ int mob_skill_log;
+ int battle_log;
+ int save_log;
+ int error_log;
+ int etc_log;
+ int save_clothcolor;
+ int undead_detect_type;
+ int pc_auto_counter_type;
+ int monster_auto_counter_type;
+ int agi_penaly_type;
+ int agi_penaly_count;
+ int agi_penaly_num;
+ int vit_penaly_type;
+ int vit_penaly_count;
+ int vit_penaly_num;
+ int player_defense_type;
+ int monster_defense_type;
+ int pet_defense_type;
+ int magic_defense_type;
+ int pc_skill_reiteration;
+ int monster_skill_reiteration;
+ int pc_skill_nofootset;
+ int monster_skill_nofootset;
+ int pc_cloak_check_type;
+ int monster_cloak_check_type;
+ int gvg_short_damage_rate;
+ int gvg_long_damage_rate;
+ int gvg_magic_damage_rate;
+ int gvg_misc_damage_rate;
+ int gvg_eliminate_time;
+ int mob_changetarget_byskill;
+ int pc_attack_direction_change;
+ int monster_attack_direction_change;
+ int pc_undead_nofreeze;
+ int pc_land_skill_limit;
+ int monster_land_skill_limit;
+ int party_skill_penaly;
+ int monster_class_change_full_recover;
+ int produce_item_name_input;
+ int produce_potion_name_input;
+ int making_arrow_name_input;
+ int holywater_name_input;
+ int display_delay_skill_fail;
+ int chat_warpportal;
+ int mob_warpportal;
+ int dead_branch_active;
+ int vending_max_value;
+// int pet_lootitem; // removed [Valaris]
+// int pet_weight; // removed [Valaris]
+ int show_steal_in_same_party;
+ int enable_upper_class;
+ int pet_attack_attr_none;
+ int mob_attack_attr_none;
+ int mob_ghostring_fix;
+ int pc_attack_attr_none;
+ int item_rate_common,item_rate_card,item_rate_equip,item_rate_heal,item_rate_use; // Added by RoVeRT, Additional Heal and Usable item rate by Val
+ int item_drop_common_min,item_drop_common_max; // Added by TyrNemesis^
+ int item_drop_card_min,item_drop_card_max;
+ int item_drop_equip_min,item_drop_equip_max;
+ int item_drop_mvp_min,item_drop_mvp_max; // End Addition
+ int item_drop_heal_min,item_drop_heal_max; // Added by Valatris
+ int item_drop_use_min,item_drop_use_max; //End
+
+ int prevent_logout; // Added by RoVeRT
+
+ int alchemist_summon_reward; // [Valaris]
+ int maximum_level;
+ int drops_by_luk;
+ int monsters_ignore_gm;
+ int equipment_breaking;
+ int equipment_break_rate;
+ int pet_equip_required;
+ int multi_level_up;
+ int pk_mode;
+ int show_mob_hp; // end additions [Valaris]
+
+ int agi_penaly_count_lv;
+ int vit_penaly_count_lv;
+
+ int gx_allhit;
+ int gx_cardfix;
+ int gx_dupele;
+ int gx_disptype;
+ int player_skill_partner_check;
+ int hide_GM_session;
+ int unit_movement_type;
+ int invite_request_check;
+ int skill_removetrap_type;
+ int disp_experience;
+ int castle_defense_rate;
+ int riding_weight;
+ int backstab_bow_penalty;
+
+ int night_at_start; // added by [Yor]
+ int day_duration; // added by [Yor]
+ int night_duration; // added by [Yor]
+ int ban_spoof_namer; // added by [Yor]
+ int hack_info_GM_level; // added by [Yor]
+ int any_warp_GM_min_level; // added by [Yor]
+ int packet_ver_flag; // added by [Yor]
+ int muting_players; // added by [Apple]
+
+ int min_hair_style; // added by [MouseJstr]
+ int max_hair_style; // added by [MouseJstr]
+ int min_hair_color; // added by [MouseJstr]
+ int max_hair_color; // added by [MouseJstr]
+ int min_cloth_color; // added by [MouseJstr]
+ int max_cloth_color; // added by [MouseJstr]
+
+ int castrate_dex_scale; // added by [MouseJstr]
+ int area_size; // added by [MouseJstr]
+
+#ifndef TXT_ONLY /* SQL-only options */
+ int mail_system; // [Valaris]
+#endif
+
+} battle_config;
+
+extern int battle_config_read(const char *cfgName);
+extern void battle_validate_conf();
+extern void battle_set_defaults();
+extern int battle_set_value(char *, char *);
+
+#endif
diff --git a/src/map/chat.c b/src/map/chat.c
new file mode 100644
index 000000000..e5e9646d1
--- /dev/null
+++ b/src/map/chat.c
@@ -0,0 +1,373 @@
+// $Id: chat.c,v 1.2 2004/09/22 02:59:47 Akitasha Exp $
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db.h"
+#include "nullpo.h"
+#include "malloc.h"
+#include "map.h"
+#include "clif.h"
+#include "pc.h"
+#include "chat.h"
+#include "npc.h"
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+int chat_triggerevent(struct chat_data *cd);
+
+
+/*==========================================
+ * チャットルーム作成
+ *------------------------------------------
+ */
+int chat_createchat(struct map_session_data *sd,int limit,int pub,char* pass,char* title,int titlelen)
+{
+ struct chat_data *cd;
+
+ nullpo_retr(0, sd);
+
+ cd = aCalloc(1,sizeof(struct chat_data));
+
+ cd->limit = limit;
+ cd->pub = pub;
+ cd->users = 1;
+ memcpy(cd->pass,pass,8);
+ if(titlelen>=sizeof(cd->title)-1) titlelen=sizeof(cd->title)-1;
+ memcpy(cd->title,title,titlelen);
+ cd->title[titlelen]=0;
+
+ cd->owner = (struct block_list **)(&cd->usersd[0]);
+ cd->usersd[0] = sd;
+ cd->bl.m = sd->bl.m;
+ cd->bl.x = sd->bl.x;
+ cd->bl.y = sd->bl.y;
+ cd->bl.type = BL_CHAT;
+
+ cd->bl.id = map_addobject(&cd->bl);
+ if(cd->bl.id==0){
+ clif_createchat(sd,1);
+ free(cd);
+ return 0;
+ }
+ pc_setchatid(sd,cd->bl.id);
+
+ clif_createchat(sd,0);
+ clif_dispchat(cd,0);
+
+ return 0;
+}
+
+/*==========================================
+ * 既存チャットルームに参加
+ *------------------------------------------
+ */
+int chat_joinchat(struct map_session_data *sd,int chatid,char* pass)
+{
+ struct chat_data *cd;
+
+ nullpo_retr(0, sd);
+
+ cd=(struct chat_data*)map_id2bl(chatid);
+ if(cd==NULL)
+ return 1;
+
+ if(cd->bl.m != sd->bl.m || cd->limit <= cd->users){
+ clif_joinchatfail(sd,0);
+ return 0;
+ }
+ if(cd->pub==0 && strncmp(pass,cd->pass,8)){
+ clif_joinchatfail(sd,1);
+ return 0;
+ }
+
+ cd->usersd[cd->users] = sd;
+ cd->users++;
+
+ pc_setchatid(sd,cd->bl.id);
+
+
+ clif_joinchatok(sd,cd); // 新たに参加した人には全員のリスト
+ clif_addchat(cd,sd); // 既に中に居た人には追加した人の報告
+ clif_dispchat(cd,0); // 周囲の人には人数変化報告
+
+ chat_triggerevent(cd); // イベント
+
+ return 0;
+}
+
+/*==========================================
+ * チャットルームから抜ける
+ *------------------------------------------
+ */
+int chat_leavechat(struct map_session_data *sd)
+{
+ struct chat_data *cd;
+ int i,leavechar;
+
+ nullpo_retr(1, sd);
+
+ cd=(struct chat_data*)map_id2bl(sd->chatID);
+ if(cd==NULL)
+ return 1;
+
+ for(i = 0,leavechar=-1;i < cd->users;i++){
+ if(cd->usersd[i] == sd){
+ leavechar=i;
+ break;
+ }
+ }
+ if(leavechar<0) // そのchatに所属していないらしい (バグ時のみ)
+ return -1;
+
+ if(leavechar==0 && cd->users>1 && (*cd->owner)->type==BL_PC){
+ // 所有者だった&他に人が居る&PCのチャット
+ clif_changechatowner(cd,cd->usersd[1]);
+ clif_clearchat(cd,0);
+ }
+
+ // 抜けるPCにも送るのでusersを減らす前に実行
+ clif_leavechat(cd,sd);
+
+ cd->users--;
+ pc_setchatid(sd,0);
+
+ if(cd->users == 0 && (*cd->owner)->type==BL_PC){
+ // 全員居なくなった&PCのチャットなので消す
+ clif_clearchat(cd,0);
+ map_delobject(cd->bl.id); // freeまでしてくれる
+ } else {
+ for(i=leavechar;i < cd->users;i++)
+ cd->usersd[i] = cd->usersd[i+1];
+ if(leavechar==0 && (*cd->owner)->type==BL_PC){
+ // PCのチャットなので所有者が抜けたので位置変更
+ cd->bl.x=cd->usersd[0]->bl.x;
+ cd->bl.y=cd->usersd[0]->bl.y;
+ }
+ clif_dispchat(cd,0);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * チャットルームの持ち主を譲る
+ *------------------------------------------
+ */
+int chat_changechatowner(struct map_session_data *sd,char *nextownername)
+{
+ struct chat_data *cd;
+ struct map_session_data *tmp_sd;
+ int i,nextowner;
+
+ nullpo_retr(1, sd);
+
+ cd=(struct chat_data*)map_id2bl(sd->chatID);
+ if(cd==NULL || (struct block_list *)sd!=(*cd->owner))
+ return 1;
+
+ for(i = 1,nextowner=-1;i < cd->users;i++){
+ if(strcmp(cd->usersd[i]->status.name,nextownername)==0){
+ nextowner=i;
+ break;
+ }
+ }
+ if(nextowner<0) // そんな人は居ない
+ return -1;
+
+ clif_changechatowner(cd,cd->usersd[nextowner]);
+ // 一旦消す
+ clif_clearchat(cd,0);
+
+ // userlistの順番変更 (0が所有者なので)
+ if( (tmp_sd = cd->usersd[0]) == NULL )
+ return 1; //ありえるのかな?
+ cd->usersd[0] = cd->usersd[nextowner];
+ cd->usersd[nextowner] = tmp_sd;
+
+ // 新しい所有者の位置へ変更
+ cd->bl.x=cd->usersd[0]->bl.x;
+ cd->bl.y=cd->usersd[0]->bl.y;
+
+ // 再度表示
+ clif_dispchat(cd,0);
+
+ return 0;
+}
+
+/*==========================================
+ * チャットの状態(タイトル等)を変更
+ *------------------------------------------
+ */
+int chat_changechatstatus(struct map_session_data *sd,int limit,int pub,char* pass,char* title,int titlelen)
+{
+ struct chat_data *cd;
+
+ nullpo_retr(1, sd);
+
+ cd=(struct chat_data*)map_id2bl(sd->chatID);
+ if(cd==NULL || (struct block_list *)sd!=(*cd->owner))
+ return 1;
+
+ cd->limit = limit;
+ cd->pub = pub;
+ memcpy(cd->pass,pass,8);
+ if(titlelen>=sizeof(cd->title)-1) titlelen=sizeof(cd->title)-1;
+ memcpy(cd->title,title,titlelen);
+ cd->title[titlelen]=0;
+
+ clif_changechatstatus(cd);
+ clif_dispchat(cd,0);
+
+ return 0;
+}
+
+/*==========================================
+ * チャットルームから蹴り出す
+ *------------------------------------------
+ */
+int chat_kickchat(struct map_session_data *sd,char *kickusername)
+{
+ struct chat_data *cd;
+ int i,kickuser;
+
+ nullpo_retr(1, sd);
+
+ cd=(struct chat_data*)map_id2bl(sd->chatID);
+ if(cd==NULL || (struct block_list *)sd!=(*cd->owner))
+ return 1;
+
+ for(i = 0,kickuser=-1;i < cd->users;i++){
+ if(strcmp(cd->usersd[i]->status.name,kickusername)==0){
+ kickuser=i;
+ break;
+ }
+ }
+ if(kickuser<0) // そんな人は居ない
+ return -1;
+
+ chat_leavechat(cd->usersd[kickuser]);
+
+ return 0;
+}
+
+/*==========================================
+ * npcチャットルーム作成
+ *------------------------------------------
+ */
+int chat_createnpcchat(struct npc_data *nd,int limit,int pub,int trigger,char* title,int titlelen,const char *ev)
+{
+ struct chat_data *cd;
+
+ nullpo_retr(1, nd);
+
+ cd = aCalloc(1,sizeof(struct chat_data));
+
+ cd->limit = cd->trigger = limit;
+ if(trigger>0)
+ cd->trigger = trigger;
+ cd->pub = pub;
+ cd->users = 0;
+ memcpy(cd->pass,"",8);
+ if(titlelen>=sizeof(cd->title)-1) titlelen=sizeof(cd->title)-1;
+ memcpy(cd->title,title,titlelen);
+ cd->title[titlelen]=0;
+
+ cd->bl.m = nd->bl.m;
+ cd->bl.x = nd->bl.x;
+ cd->bl.y = nd->bl.y;
+ cd->bl.type = BL_CHAT;
+ cd->owner_ = (struct block_list *)nd;
+ cd->owner = &cd->owner_;
+ memcpy(cd->npc_event,ev,sizeof(cd->npc_event));
+
+ cd->bl.id = map_addobject(&cd->bl);
+ if(cd->bl.id==0){
+ free(cd);
+ return 0;
+ }
+ nd->chat_id=cd->bl.id;
+
+ clif_dispchat(cd,0);
+
+ return 0;
+}
+/*==========================================
+ * npcチャットルーム削除
+ *------------------------------------------
+ */
+int chat_deletenpcchat(struct npc_data *nd)
+{
+ struct chat_data *cd;
+
+ nullpo_retr(0, nd);
+ nullpo_retr(0, cd=(struct chat_data*)map_id2bl(nd->chat_id));
+
+ chat_npckickall(cd);
+ clif_clearchat(cd,0);
+ map_delobject(cd->bl.id); // freeまでしてくれる
+ nd->chat_id=0;
+
+ return 0;
+}
+
+/*==========================================
+ * 規定人数以上でイベントが定義されてるなら実行
+ *------------------------------------------
+ */
+int chat_triggerevent(struct chat_data *cd)
+{
+ nullpo_retr(0, cd);
+
+ if(cd->users>=cd->trigger && cd->npc_event[0])
+ npc_event_do(cd->npc_event);
+ return 0;
+}
+
+/*==========================================
+ * イベントの有効化
+ *------------------------------------------
+ */
+int chat_enableevent(struct chat_data *cd)
+{
+ nullpo_retr(0, cd);
+
+ cd->trigger&=0x7f;
+ chat_triggerevent(cd);
+ return 0;
+}
+/*==========================================
+ * イベントの無効化
+ *------------------------------------------
+ */
+int chat_disableevent(struct chat_data *cd)
+{
+ nullpo_retr(0, cd);
+
+ cd->trigger|=0x80;
+ return 0;
+}
+/*==========================================
+ * チャットルームから全員蹴り出す
+ *------------------------------------------
+ */
+int chat_npckickall(struct chat_data *cd)
+{
+ nullpo_retr(0, cd);
+
+ while(cd->users>0){
+ chat_leavechat(cd->usersd[cd->users-1]);
+ }
+ return 0;
+}
+
+/*==========================================
+ * 終了
+ *------------------------------------------
+ */
+int do_final_chat(void)
+{
+ return 0;
+}
diff --git a/src/map/chat.h b/src/map/chat.h
new file mode 100644
index 000000000..15559f188
--- /dev/null
+++ b/src/map/chat.h
@@ -0,0 +1,22 @@
+// $Id: chat.h,v 1.3 2004/09/25 05:32:18 MouseJstr Exp $
+#ifndef _CHAT_H_
+#define _CHAT_H_
+
+#include "map.h"
+
+int chat_createchat(struct map_session_data *,int,int,char*,char*,int);
+int chat_joinchat(struct map_session_data *,int,char*);
+int chat_leavechat(struct map_session_data* );
+int chat_changechatowner(struct map_session_data *,char *);
+int chat_changechatstatus(struct map_session_data *,int,int,char*,char*,int);
+int chat_kickchat(struct map_session_data *,char *);
+
+int chat_createnpcchat(struct npc_data *nd,int limit,int pub,int trigger,char* title,int titlelen,const char *ev);
+int chat_deletenpcchat(struct npc_data *nd);
+int chat_enableevent(struct chat_data *cd);
+int chat_disableevent(struct chat_data *cd);
+int chat_npckickall(struct chat_data *cd);
+
+int do_final_chat(void);
+
+#endif
diff --git a/src/map/chrif.c b/src/map/chrif.c
new file mode 100644
index 000000000..0c456f128
--- /dev/null
+++ b/src/map/chrif.c
@@ -0,0 +1,1016 @@
+// $Id: chrif.c,v 1.6 2004/09/25 11:39:17 MouseJstr Exp $
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _WIN32
+#include <winsock.h>
+#else
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#include <sys/types.h>
+#include <time.h>
+
+#include "socket.h"
+#include "timer.h"
+#include "map.h"
+#include "battle.h"
+#include "chrif.h"
+#include "clif.h"
+#include "intif.h"
+#include "npc.h"
+#include "pc.h"
+#include "nullpo.h"
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+static const int packet_len_table[0x20] = {
+ 60, 3,-1,27,22,-1, 6,-1, // 2af8-2aff
+ 6,-1,18, 7,-1,49,44, 0, // 2b00-2b07
+ 6,30,-1,10,86, 7,44,34, // 2b08-2b0f
+ -1,-1,10, 6,11,-1, 0, 0, // 2b10-2b17
+};
+
+int char_fd;
+int srvinfo;
+static char char_ip_str[16];
+static int char_ip;
+static int char_port = 6121;
+static char userid[24], passwd[24];
+static int chrif_state;
+
+// 設定ファイル読み込み関係
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void chrif_setuserid(char *id)
+{
+ strncpy(userid, id, 24);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void chrif_setpasswd(char *pwd)
+{
+ strncpy(passwd, pwd, 24);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void chrif_setip(char *ip)
+{
+ strncpy(char_ip_str, ip, 16);
+ char_ip = inet_addr(char_ip_str);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void chrif_setport(int port)
+{
+ char_port = port;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int chrif_isconnect(void)
+{
+ return chrif_state == 2;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int chrif_save(struct map_session_data *sd)
+{
+ nullpo_retr(-1, sd);
+
+ if (char_fd < 0)
+ return -1;
+
+ pc_makesavestatus(sd);
+
+ WFIFOW(char_fd,0) = 0x2b01;
+ WFIFOW(char_fd,2) = sizeof(sd->status) + 12;
+ WFIFOL(char_fd,4) = sd->bl.id;
+ WFIFOL(char_fd,8) = sd->char_id;
+ memcpy(WFIFOP(char_fd,12), &sd->status, sizeof(sd->status));
+ WFIFOSET(char_fd, WFIFOW(char_fd,2));
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int chrif_connect(int fd)
+{
+ WFIFOW(fd,0) = 0x2af8;
+ memcpy(WFIFOP(fd,2), userid, 24);
+ memcpy(WFIFOP(fd,26), passwd, 24);
+ WFIFOL(fd,50) = 0;
+ WFIFOL(fd,54) = clif_getip();
+ WFIFOW(fd,58) = clif_getport(); // [Valaris] thanks to fov
+ WFIFOSET(fd,60);
+
+ return 0;
+}
+
+/*==========================================
+ * マップ送信
+ *------------------------------------------
+ */
+int chrif_sendmap(int fd)
+{
+ int i;
+
+ WFIFOW(fd,0) = 0x2afa;
+ for(i = 0; i < map_num; i++)
+ if (map[i].alias[0] != '\0') // [MouseJstr] map aliasing
+ memcpy(WFIFOP(fd,4+i*16), map[i].alias, 16);
+ else
+ memcpy(WFIFOP(fd,4+i*16), map[i].name, 16);
+ WFIFOW(fd,2) = 4 + i * 16;
+ WFIFOSET(fd,WFIFOW(fd,2));
+
+ return 0;
+}
+
+/*==========================================
+ * マップ受信
+ *------------------------------------------
+ */
+int chrif_recvmap(int fd)
+{
+ int i, j, ip, port;
+ unsigned char *p = (unsigned char *)&ip;
+
+ if (chrif_state < 2) // まだ準備中
+ return -1;
+
+ ip = RFIFOL(fd,4);
+ port = RFIFOW(fd,8);
+ for(i = 10, j = 0; i < RFIFOW(fd,2); i += 16, j++) {
+ map_setipport(RFIFOP(fd,i), ip, port);
+// if (battle_config.etc_log)
+// printf("recv map %d %s\n", j, RFIFOP(fd,i));
+ }
+ if (battle_config.etc_log)
+ printf("recv map on %d.%d.%d.%d:%d (%d maps)\n", p[0], p[1], p[2], p[3], port, j);
+
+ return 0;
+}
+
+/*==========================================
+ * マップ鯖間移動のためのデータ準備要求
+ *------------------------------------------
+ */
+int chrif_changemapserver(struct map_session_data *sd, char *name, int x, int y, int ip, short port)
+{
+ int i, s_ip;
+
+ nullpo_retr(-1, sd);
+
+ s_ip = 0;
+ for(i = 0; i < fd_max; i++)
+ if (session[i] && session[i]->session_data == sd) {
+ s_ip = session[i]->client_addr.sin_addr.s_addr;
+ break;
+ }
+
+ WFIFOW(char_fd, 0) = 0x2b05;
+ WFIFOL(char_fd, 2) = sd->bl.id;
+ WFIFOL(char_fd, 6) = sd->login_id1;
+ WFIFOL(char_fd,10) = sd->login_id2;
+ WFIFOL(char_fd,14) = sd->status.char_id;
+ memcpy(WFIFOP(char_fd,18), name, 16);
+ WFIFOW(char_fd,34) = x;
+ WFIFOW(char_fd,36) = y;
+ WFIFOL(char_fd,38) = ip;
+ WFIFOL(char_fd,42) = port;
+ WFIFOB(char_fd,44) = sd->status.sex;
+ WFIFOL(char_fd,45) = s_ip;
+ WFIFOSET(char_fd,49);
+
+ return 0;
+}
+
+/*==========================================
+ * マップ鯖間移動ack
+ *------------------------------------------
+ */
+int chrif_changemapserverack(int fd)
+{
+ struct map_session_data *sd = map_id2sd(RFIFOL(fd,2));
+
+ if (sd == NULL || sd->status.char_id != RFIFOL(fd,14))
+ return -1;
+
+ if (RFIFOL(fd,6) == 1) {
+ if (battle_config.error_log)
+ printf("map server change failed.\n");
+ pc_authfail(sd->fd);
+ return 0;
+ }
+ clif_changemapserver(sd, RFIFOP(fd,18), RFIFOW(fd,34), RFIFOW(fd,36), RFIFOL(fd,38), RFIFOW(fd,42));
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int chrif_connectack(int fd)
+{
+ if (RFIFOB(fd,2)) {
+ printf("Connected to char-server failed %d.\n", RFIFOB(fd,2));
+ exit(1);
+ }
+ printf("Connected to char-server (connection #%d).\n", fd);
+ chrif_state = 1;
+
+ chrif_sendmap(fd);
+
+ printf("chrif: OnCharIfInit event done. (%d events)\n", npc_event_doall("OnCharIfInit"));
+ printf("chrif: OnInterIfInit event done. (%d events)\n", npc_event_doall("OnInterIfInit"));
+
+ // <Agit> Run Event [AgitInit]
+// printf("NPC_Event:[OnAgitInit] do (%d) events (Agit Initialize).\n", npc_event_doall("OnAgitInit"));
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int chrif_sendmapack(int fd)
+{
+ if (RFIFOB(fd,2)) {
+ printf("chrif : send map list to char server failed %d\n", RFIFOB(fd,2));
+ exit(1);
+ }
+
+ memcpy(wisp_server_name, RFIFOP(fd,3), 24);
+
+ chrif_state = 2;
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int chrif_authreq(struct map_session_data *sd)
+{
+ int i;
+
+ nullpo_retr(-1, sd);
+
+ if (!sd || !char_fd || !sd->bl.id || !sd->login_id1)
+ return -1;
+
+ for(i = 0; i < fd_max; i++)
+ if (session[i] && session[i]->session_data == sd) {
+ WFIFOW(char_fd, 0) = 0x2afc;
+ WFIFOL(char_fd, 2) = sd->bl.id;
+ WFIFOL(char_fd, 6) = sd->char_id;
+ WFIFOL(char_fd,10) = sd->login_id1;
+ WFIFOL(char_fd,14) = sd->login_id2;
+ WFIFOL(char_fd,18) = session[i]->client_addr.sin_addr.s_addr;
+ WFIFOSET(char_fd,22);
+ break;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int chrif_charselectreq(struct map_session_data *sd)
+{
+ int i, s_ip;
+
+ nullpo_retr(-1, sd);
+
+ if(!sd || !char_fd || !sd->bl.id || !sd->login_id1)
+ return -1;
+
+ s_ip = 0;
+ for(i = 0; i < fd_max; i++)
+ if (session[i] && session[i]->session_data == sd) {
+ s_ip = session[i]->client_addr.sin_addr.s_addr;
+ break;
+ }
+
+ WFIFOW(char_fd, 0) = 0x2b02;
+ WFIFOL(char_fd, 2) = sd->bl.id;
+ WFIFOL(char_fd, 6) = sd->login_id1;
+ WFIFOL(char_fd,10) = sd->login_id2;
+ WFIFOL(char_fd,14) = s_ip;
+ WFIFOSET(char_fd,18);
+
+ return 0;
+}
+
+/*==========================================
+ * キャラ名問い合わせ
+ *------------------------------------------
+ */
+int chrif_searchcharid(int char_id)
+{
+ if (!char_id)
+ return -1;
+
+ WFIFOW(char_fd,0) = 0x2b08;
+ WFIFOL(char_fd,2) = char_id;
+ WFIFOSET(char_fd,6);
+
+ return 0;
+}
+
+/*==========================================
+ * GMに変化要求
+ *------------------------------------------
+ */
+int chrif_changegm(int id, const char *pass, int len)
+{
+ if (battle_config.etc_log)
+ printf("chrif_changegm: account: %d, password: '%s'.\n", id, pass);
+
+ WFIFOW(char_fd,0) = 0x2b0a;
+ WFIFOW(char_fd,2) = len + 8;
+ WFIFOL(char_fd,4) = id;
+ memcpy(WFIFOP(char_fd,8), pass, len);
+ WFIFOSET(char_fd, len + 8);
+
+ return 0;
+}
+
+/*==========================================
+ * Change Email
+ *------------------------------------------
+ */
+int chrif_changeemail(int id, const char *actual_email, const char *new_email)
+{
+ if (battle_config.etc_log)
+ printf("chrif_changeemail: account: %d, actual_email: '%s', new_email: '%s'.\n", id, actual_email, new_email);
+
+ WFIFOW(char_fd,0) = 0x2b0c;
+ WFIFOL(char_fd,2) = id;
+ memcpy(WFIFOP(char_fd,6), actual_email, 40);
+ memcpy(WFIFOP(char_fd,46), new_email, 40);
+ WFIFOSET(char_fd,86);
+
+ return 0;
+}
+
+/*==========================================
+ * Send message to char-server with a character name to do some operations (by Yor)
+ * Used to ask Char-server about a character name to have the account number to modify account file in login-server.
+ * type of operation:
+ * 1: block
+ * 2: ban
+ * 3: unblock
+ * 4: unban
+ * 5: changesex
+ *------------------------------------------
+ */
+int chrif_char_ask_name(int id, char * character_name, short operation_type, int year, int month, int day, int hour, int minute, int second)
+{
+ WFIFOW(char_fd, 0) = 0x2b0e;
+ WFIFOL(char_fd, 2) = id; // account_id of who ask (for answer) -1 if nobody
+ memcpy(WFIFOP(char_fd,6), character_name, 24);
+ WFIFOW(char_fd, 30) = operation_type; // type of operation
+ if (operation_type == 2) {
+ WFIFOW(char_fd, 32) = year;
+ WFIFOW(char_fd, 34) = month;
+ WFIFOW(char_fd, 36) = day;
+ WFIFOW(char_fd, 38) = hour;
+ WFIFOW(char_fd, 40) = minute;
+ WFIFOW(char_fd, 42) = second;
+ }
+ printf("chrif : sended 0x2b0e\n");
+ WFIFOSET(char_fd,44);
+
+ return 0;
+}
+
+/*==========================================
+ * Answer after a request about a character name to do some operations (by Yor)
+ * Used to answer of chrif_char_ask_name.
+ * type of operation:
+ * 1: block
+ * 2: ban
+ * 3: unblock
+ * 4: unban
+ * 5: changesex
+ * type of answer:
+ * 0: login-server resquest done
+ * 1: player not found
+ * 2: gm level too low
+ * 3: login-server offline
+ *------------------------------------------
+ */
+int chrif_char_ask_name_answer(int fd)
+{
+ int acc;
+ struct map_session_data *sd;
+ char output[256];
+ char player_name[24];
+
+ acc = RFIFOL(fd,2); // account_id of who has asked (-1 if nobody)
+ memcpy(player_name, RFIFOP(fd,6), sizeof(player_name));
+ player_name[sizeof(player_name)-1] = '\0';
+
+ sd = map_id2sd(acc);
+ if (acc >= 0 && sd != NULL) {
+ if (RFIFOW(fd, 32) == 1) // player not found
+ sprintf(output, "The player '%s' doesn't exist.", player_name);
+ else {
+ switch(RFIFOW(fd, 30)) {
+ case 1: // block
+ switch(RFIFOW(fd, 32)) {
+ case 0: // login-server resquest done
+ sprintf(output, "Login-server has been asked to block the player '%s'.", player_name);
+ break;
+ //case 1: // player not found
+ case 2: // gm level too low
+ sprintf(output, "Your GM level don't authorise you to block the player '%s'.", player_name);
+ break;
+ case 3: // login-server offline
+ sprintf(output, "Login-server is offline. Impossible to block the the player '%s'.", player_name);
+ break;
+ }
+ break;
+ case 2: // ban
+ switch(RFIFOW(fd, 32)) {
+ case 0: // login-server resquest done
+ sprintf(output, "Login-server has been asked to ban the player '%s'.", player_name);
+ break;
+ //case 1: // player not found
+ case 2: // gm level too low
+ sprintf(output, "Your GM level don't authorise you to ban the player '%s'.", player_name);
+ break;
+ case 3: // login-server offline
+ sprintf(output, "Login-server is offline. Impossible to ban the the player '%s'.", player_name);
+ break;
+ }
+ break;
+ case 3: // unblock
+ switch(RFIFOW(fd, 32)) {
+ case 0: // login-server resquest done
+ sprintf(output, "Login-server has been asked to unblock the player '%s'.", player_name);
+ break;
+ //case 1: // player not found
+ case 2: // gm level too low
+ sprintf(output, "Your GM level don't authorise you to unblock the player '%s'.", player_name);
+ break;
+ case 3: // login-server offline
+ sprintf(output, "Login-server is offline. Impossible to unblock the the player '%s'.", player_name);
+ break;
+ }
+ break;
+ case 4: // unban
+ switch(RFIFOW(fd, 32)) {
+ case 0: // login-server resquest done
+ sprintf(output, "Login-server has been asked to unban the player '%s'.", player_name);
+ break;
+ //case 1: // player not found
+ case 2: // gm level too low
+ sprintf(output, "Your GM level don't authorise you to unban the player '%s'.", player_name);
+ break;
+ case 3: // login-server offline
+ sprintf(output, "Login-server is offline. Impossible to unban the the player '%s'.", player_name);
+ break;
+ }
+ break;
+ case 5: // changesex
+ switch(RFIFOW(fd, 32)) {
+ case 0: // login-server resquest done
+ sprintf(output, "Login-server has been asked to change the sex of the player '%s'.", player_name);
+ break;
+ //case 1: // player not found
+ case 2: // gm level too low
+ sprintf(output, "Your GM level don't authorise you to change the sex of the player '%s'.", player_name);
+ break;
+ case 3: // login-server offline
+ sprintf(output, "Login-server is offline. Impossible to change the sex of the the player '%s'.", player_name);
+ break;
+ }
+ break;
+ }
+ }
+ if (output[0] != '\0') {
+ output[sizeof(output)-1] = '\0';
+ clif_displaymessage(sd->fd, output);
+ }
+ } else
+ printf("chrif_char_ask_name_answer failed - player not online.\n");
+
+ return 0;
+}
+
+/*==========================================
+ * End of GM change (@GM) (modified by Yor)
+ *------------------------------------------
+ */
+int chrif_changedgm(int fd)
+{
+ int acc, level;
+ struct map_session_data *sd = NULL;
+
+ acc = RFIFOL(fd,2);
+ level = RFIFOL(fd,6);
+
+ sd = map_id2sd(acc);
+
+ if (battle_config.etc_log)
+ printf("chrif_changedgm: account: %d, GM level 0 -> %d.\n", acc, level);
+ if (sd != NULL) {
+ if (level > 0)
+ clif_displaymessage(sd->fd, "GM modification success.");
+ else
+ clif_displaymessage(sd->fd, "Failure of GM modification.");
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 性別変化終了 (modified by Yor)
+ *------------------------------------------
+ */
+int chrif_changedsex(int fd)
+{
+ int acc, sex, i;
+ struct map_session_data *sd;
+ struct pc_base_job s_class;
+
+ acc = RFIFOL(fd,2);
+ sex = RFIFOL(fd,6);
+ if (battle_config.etc_log)
+ printf("chrif_changedsex %d.\n", acc);
+ sd = map_id2sd(acc);
+ if (acc > 0) {
+ if (sd != NULL && sd->status.sex != sex) {
+ s_class = pc_calc_base_job(sd->status.class);
+ if (sd->status.sex == 0) {
+ sd->status.sex = 1;
+ sd->sex = 1;
+ } else if (sd->status.sex == 1) {
+ sd->status.sex = 0;
+ sd->sex = 0;
+ }
+ // to avoid any problem with equipment and invalid sex, equipment is unequiped.
+ for (i = 0; i < MAX_INVENTORY; i++) {
+ if (sd->status.inventory[i].nameid && sd->status.inventory[i].equip)
+ pc_unequipitem((struct map_session_data*)sd, i, 0);
+ }
+ // reset skill of some job
+ if (s_class.job == 19 || s_class.job == 4020 || s_class.job == 4042 ||
+ s_class.job == 20 || s_class.job == 4021 || s_class.job == 4043) {
+ // remove specifical skills of classes 19, 4020 and 4042
+ for(i = 315; i <= 322; i++) {
+ if (sd->status.skill[i].id > 0 && !sd->status.skill[i].flag) {
+ sd->status.skill_point += sd->status.skill[i].lv;
+ sd->status.skill[i].id = 0;
+ sd->status.skill[i].lv = 0;
+ }
+ }
+ // remove specifical skills of classes 20, 4021 and 4043
+ for(i = 323; i <= 330; i++) {
+ if (sd->status.skill[i].id > 0 && !sd->status.skill[i].flag) {
+ sd->status.skill_point += sd->status.skill[i].lv;
+ sd->status.skill[i].id = 0;
+ sd->status.skill[i].lv = 0;
+ }
+ }
+ clif_updatestatus(sd, SP_SKILLPOINT);
+ // change job if necessary
+ if (s_class.job == 20 || s_class.job == 4021 || s_class.job == 4043)
+ sd->status.class -= 1;
+ else if (s_class.job == 19 || s_class.job == 4020 || s_class.job == 4042)
+ sd->status.class += 1;
+ }
+ // save character
+ chrif_save(sd);
+ sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters
+ // do same modify in login-server for the account, but no in char-server (it ask again login_id1 to login, and don't remember it)
+ clif_displaymessage(sd->fd, "Your sex has been changed (need disconexion by the server)...");
+ clif_setwaitclose(sd->fd); // forced to disconnect for the change
+ }
+ } else {
+ if (sd != NULL) {
+ printf("chrif_changedsex failed.\n");
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * アカウント変数保存要求
+ *------------------------------------------
+ */
+int chrif_saveaccountreg2(struct map_session_data *sd)
+{
+ int p, j;
+ nullpo_retr(-1, sd);
+
+ p = 8;
+ for(j = 0; j < sd->status.account_reg2_num; j++) {
+ struct global_reg *reg = &sd->status.account_reg2[j];
+ if (reg->str[0] && reg->value != 0) {
+ memcpy(WFIFOP(char_fd,p), reg->str, 32);
+ WFIFOL(char_fd,p+32) = reg->value;
+ p += 36;
+ }
+ }
+ WFIFOW(char_fd,0) = 0x2b10;
+ WFIFOW(char_fd,2) = p;
+ WFIFOL(char_fd,4) = sd->bl.id;
+ WFIFOSET(char_fd,p);
+
+ return 0;
+}
+
+/*==========================================
+ * アカウント変数通知
+ *------------------------------------------
+ */
+int chrif_accountreg2(int fd)
+{
+ int j, p;
+ struct map_session_data *sd;
+
+ if ((sd = map_id2sd(RFIFOL(fd,4))) == NULL)
+ return 1;
+
+ for(p = 8, j = 0; p < RFIFOW(fd,2) && j < ACCOUNT_REG2_NUM; p += 36, j++) {
+ memcpy(sd->status.account_reg2[j].str, RFIFOP(fd,p), 32);
+ sd->status.account_reg2[j].value = RFIFOL(fd, p + 32);
+ }
+ sd->status.account_reg2_num = j;
+// printf("chrif: accountreg2\n");
+
+ return 0;
+}
+
+/*==========================================
+ * 離婚情報同期要求
+ *------------------------------------------
+ */
+int chrif_divorce(int char_id, int partner_id)
+{
+ struct map_session_data *sd = NULL;
+
+ if (!char_id || !partner_id)
+ return 0;
+
+ nullpo_retr(0, sd = map_nick2sd(map_charid2nick(partner_id)));
+ if (sd->status.partner_id == char_id) {
+ int i;
+ //離婚(相方は既にキャラが消えている筈なので)
+ sd->status.partner_id = 0;
+
+ //相方の結婚指輪を剥奪
+ for(i = 0; i < MAX_INVENTORY; i++)
+ if (sd->status.inventory[i].nameid == WEDDING_RING_M || sd->status.inventory[i].nameid == WEDDING_RING_F)
+ pc_delitem(sd, i, 1, 0);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * Disconnection of a player (account has been deleted in login-server) by [Yor]
+ *------------------------------------------
+ */
+int chrif_accountdeletion(int fd)
+{
+ int acc;
+ struct map_session_data *sd;
+
+ acc = RFIFOL(fd,2);
+ if (battle_config.etc_log)
+ printf("chrif_accountdeletion %d.\n", acc);
+ sd = map_id2sd(acc);
+ if (acc > 0) {
+ if (sd != NULL) {
+ sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters
+ clif_displaymessage(sd->fd, "Your account has been deleted (disconnexion)...");
+ clif_setwaitclose(sd->fd); // forced to disconnect for the change
+ }
+ } else {
+ if (sd != NULL)
+ printf("chrif_accountdeletion failed - player not online.\n");
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * Disconnection of a player (account has been banned of has a status, from login-server) by [Yor]
+ *------------------------------------------
+ */
+int chrif_accountban(int fd)
+{
+ int acc;
+ struct map_session_data *sd;
+
+ acc = RFIFOL(fd,2);
+ if (battle_config.etc_log)
+ printf("chrif_accountban %d.\n", acc);
+ sd = map_id2sd(acc);
+ if (acc > 0) {
+ if (sd != NULL) {
+ sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters
+ if (RFIFOB(fd,6) == 0) { // 0: change of statut, 1: ban
+ switch (RFIFOL(fd,7)) { // status or final date of a banishment
+ case 1: // 0 = Unregistered ID
+ clif_displaymessage(sd->fd, "Your account has 'Unregistered'.");
+ break;
+ case 2: // 1 = Incorrect Password
+ clif_displaymessage(sd->fd, "Your account has an 'Incorrect Password'...");
+ break;
+ case 3: // 2 = This ID is expired
+ clif_displaymessage(sd->fd, "Your account has expired.");
+ break;
+ case 4: // 3 = Rejected from Server
+ clif_displaymessage(sd->fd, "Your account has been rejected from server.");
+ break;
+ case 5: // 4 = You have been blocked by the GM Team
+ clif_displaymessage(sd->fd, "Your account has been blocked by the GM Team.");
+ break;
+ case 6: // 5 = Your Game's EXE file is not the latest version
+ clif_displaymessage(sd->fd, "Your Game's EXE file is not the latest version.");
+ break;
+ case 7: // 6 = Your are Prohibited to log in until %s
+ clif_displaymessage(sd->fd, "Your account has been prohibited to log in.");
+ break;
+ case 8: // 7 = Server is jammed due to over populated
+ clif_displaymessage(sd->fd, "Server is jammed due to over populated.");
+ break;
+ case 9: // 8 = No MSG (actually, all states after 9 except 99 are No MSG, use only this)
+ clif_displaymessage(sd->fd, "Your account has not more authorised.");
+ break;
+ case 100: // 99 = This ID has been totally erased
+ clif_displaymessage(sd->fd, "Your account has been totally erased.");
+ break;
+ default:
+ clif_displaymessage(sd->fd, "Your account has not more authorised.");
+ break;
+ }
+ } else if (RFIFOB(fd,6) == 1) { // 0: change of statut, 1: ban
+ time_t timestamp;
+ char tmpstr[2048];
+ timestamp = (time_t)RFIFOL(fd,7); // status or final date of a banishment
+ strcpy(tmpstr, "Your account has been banished until ");
+ strftime(tmpstr + strlen(tmpstr), 24, "%d-%m-%Y %H:%M:%S", localtime(&timestamp));
+ clif_displaymessage(sd->fd, tmpstr);
+ }
+ clif_setwaitclose(sd->fd); // forced to disconnect for the change
+ }
+ } else {
+ if (sd != NULL)
+ printf("chrif_accountban failed - player not online.\n");
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * Receiving GM accounts and their levels from char-server by [Yor]
+ *------------------------------------------
+ */
+int chrif_recvgmaccounts(int fd)
+{
+ printf("From login-server: receiving of %d GM accounts information.\n", pc_read_gm_account(fd));
+
+ return 0;
+}
+
+/*==========================================
+ * Request to reload GM accounts and their levels: send to char-server by [Yor]
+ *------------------------------------------
+ */
+int chrif_reloadGMdb(void)
+{
+
+ WFIFOW(char_fd,0) = 0x2af7;
+ WFIFOSET(char_fd, 2);
+
+ return 0;
+}
+
+/*==========================================
+ * Send rates and motd to char server [Wizputer]
+ *------------------------------------------
+ */
+ int chrif_ragsrvinfo(int base_rate, int job_rate, int drop_rate)
+{
+ char buf[256];
+ FILE *fp;
+ int i;
+
+ WFIFOW(char_fd,0) = 0x2b16;
+ WFIFOW(char_fd,2) = base_rate;
+ WFIFOW(char_fd,4) = job_rate;
+ WFIFOW(char_fd,6) = drop_rate;
+
+ if ((fp = fopen(motd_txt, "r")) != NULL) {
+ if (fgets(buf, 250, fp) != NULL) {
+ for(i = 0; buf[i]; i++) {
+ if (buf[i] == '\r' || buf[i] == '\n') {
+ buf[i] = 0;
+ break;
+ }
+ }
+ WFIFOW(char_fd,8) = sizeof(buf) + 10;
+ memcpy(WFIFOP(char_fd,10), buf, sizeof(buf));
+ }
+ fclose(fp);
+ } else {
+ WFIFOW(char_fd,8) = sizeof(buf) + 10;
+ memcpy(WFIFOP(char_fd,10), buf, sizeof(buf));
+ }
+ WFIFOSET(char_fd,WFIFOW(char_fd,8));
+
+ return 0;
+}
+
+/*=========================================
+ * Tell char-server charcter disconnected [Wizputer]
+ *-----------------------------------------
+ */
+
+int chrif_char_offline(struct map_session_data *sd)
+{
+ if (char_fd < 0)
+ return -1;
+
+ WFIFOW(char_fd,0) = 0x2b17;
+ WFIFOL(char_fd,2) = sd->status.char_id;
+ WFIFOSET(char_fd,6);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int chrif_parse(int fd)
+{
+ int packet_len, cmd;
+
+ // only char-server can have an access to here.
+ // so, if it isn't the char-server, we disconnect the session (fd != char_fd).
+ if (fd != char_fd || session[fd]->eof) {
+ if (fd == char_fd) {
+ printf("Map-server can't connect to char-server (connection #%d).\n", fd);
+ char_fd = -1;
+ }
+ close(fd);
+ delete_session(fd);
+ return 0;
+ }
+
+ while (RFIFOREST(fd) >= 2) {
+ cmd = RFIFOW(fd,0);
+ if (cmd < 0x2af8 || cmd >= 0x2af8 + (sizeof(packet_len_table) / sizeof(packet_len_table[0])) ||
+ packet_len_table[cmd-0x2af8] == 0) {
+
+ int r = intif_parse(fd); // intifに渡す
+
+ if (r == 1) continue; // intifで処理した
+ if (r == 2) return 0; // intifで処理したが、データが足りない
+
+ session[fd]->eof = 1;
+ return 0;
+ }
+ packet_len = packet_len_table[cmd-0x2af8];
+ if (packet_len == -1) {
+ if (RFIFOREST(fd) < 4)
+ return 0;
+ packet_len = RFIFOW(fd,2);
+ }
+ if (RFIFOREST(fd) < packet_len)
+ return 0;
+
+ switch(cmd) {
+ case 0x2af9: chrif_connectack(fd); break;
+ case 0x2afb: chrif_sendmapack(fd); break;
+ case 0x2afd: pc_authok(RFIFOL(fd,4), RFIFOL(fd,8), (time_t)RFIFOL(fd,12), (struct mmo_charstatus*)RFIFOP(fd,16)); break;
+ case 0x2afe: pc_authfail(RFIFOL(fd,2)); break;
+ case 0x2b00: map_setusers(RFIFOL(fd,2)); break;
+ case 0x2b03: clif_charselectok(RFIFOL(fd,2)); break;
+ case 0x2b04: chrif_recvmap(fd); break;
+ case 0x2b06: chrif_changemapserverack(fd); break;
+ case 0x2b09: map_addchariddb(RFIFOL(fd,2), RFIFOP(fd,6)); break;
+ case 0x2b0b: chrif_changedgm(fd); break;
+ case 0x2b0d: chrif_changedsex(fd); break;
+ case 0x2b0f: chrif_char_ask_name_answer(fd); break;
+ case 0x2b11: chrif_accountreg2(fd); break;
+ case 0x2b12: chrif_divorce(RFIFOL(fd,2), RFIFOL(fd,6)); break;
+ case 0x2b13: chrif_accountdeletion(fd); break;
+ case 0x2b14: chrif_accountban(fd); break;
+ case 0x2b15: chrif_recvgmaccounts(fd); break;
+
+ default:
+ if (battle_config.error_log)
+ printf("chrif_parse : unknown packet %d %d\n", fd, RFIFOW(fd,0));
+ session[fd]->eof = 1;
+ return 0;
+ }
+ RFIFOSKIP(fd, packet_len);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * timer関数
+ * 今このmap鯖に繋がっているクライアント人数をchar鯖へ送る
+ *------------------------------------------
+ */
+int send_users_tochar(int tid, unsigned int tick, int id, int data) {
+ int users = 0, i;
+ struct map_session_data *sd;
+
+ if (char_fd <= 0 || session[char_fd] == NULL)
+ return 0;
+
+ WFIFOW(char_fd,0) = 0x2aff;
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (sd = session[i]->session_data) && sd->state.auth &&
+ !((battle_config.hide_GM_session || (sd->status.option & OPTION_HIDE)) && pc_isGM(sd))) {
+ WFIFOL(char_fd,6+4*users) = sd->status.char_id;
+ users++;
+ }
+ }
+ WFIFOW(char_fd,2) = 6 + 4 * users;
+ WFIFOW(char_fd,4) = users;
+ WFIFOSET(char_fd,6+4*users);
+
+ return 0;
+}
+
+/*==========================================
+ * timer関数
+ * char鯖との接続を確認し、もし切れていたら再度接続する
+ *------------------------------------------
+ */
+int check_connect_char_server(int tid, unsigned int tick, int id, int data) {
+ if (char_fd <= 0 || session[char_fd] == NULL) {
+ printf("Attempt to connect to char-server...\n");
+ chrif_state = 0;
+ char_fd = make_connection(char_ip, char_port);
+ session[char_fd]->func_parse = chrif_parse;
+ realloc_fifo(char_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
+
+ chrif_connect(char_fd);
+#ifndef TXT_ONLY
+ srvinfo = 0;
+ } else {
+ if (srvinfo == 0) {
+ chrif_ragsrvinfo(battle_config.base_exp_rate, battle_config.job_exp_rate, battle_config.item_rate_common);
+ srvinfo = 1;
+ }
+#endif /* not TXT_ONLY */
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int do_init_chrif(void) {
+ add_timer_func_list(check_connect_char_server, "check_connect_char_server");
+ add_timer_func_list(send_users_tochar, "send_users_tochar");
+ add_timer_interval(gettick() + 1000, check_connect_char_server, 0, 0, 10 * 1000);
+ add_timer_interval(gettick() + 1000, send_users_tochar, 0, 0, 5 * 1000);
+
+ return 0;
+}
diff --git a/src/map/chrif.h b/src/map/chrif.h
new file mode 100644
index 000000000..3408c89ef
--- /dev/null
+++ b/src/map/chrif.h
@@ -0,0 +1,29 @@
+// $Id: chrif.h,v 1.3 2004/09/25 11:39:17 MouseJstr Exp $
+#ifndef _CHRIF_H_
+#define _CHRIF_H_
+
+void chrif_setuserid(char*);
+void chrif_setpasswd(char*);
+void chrif_setip(char*);
+void chrif_setport(int);
+
+int chrif_isconnect(void);
+
+int chrif_authreq(struct map_session_data *);
+int chrif_save(struct map_session_data*);
+int chrif_charselectreq(struct map_session_data *);
+
+int chrif_changemapserver(struct map_session_data *sd,char *name,int x,int y,int ip,short port);
+
+int chrif_searchcharid(int char_id);
+int chrif_changegm(int id,const char *pass,int len);
+int chrif_changeemail(int id, const char *actual_email, const char *new_email);
+int chrif_char_ask_name(int id, char * character_name, short operation_type, int year, int month, int day, int hour, int minute, int second);
+int chrif_saveaccountreg2(struct map_session_data *sd);
+int chrif_reloadGMdb(void);
+int chrif_ragsrvinfo(int base_rate,int job_rate, int drop_rate);
+int chrif_char_offline(struct map_session_data *sd);
+
+int do_init_chrif(void);
+
+#endif
diff --git a/src/map/clif.c b/src/map/clif.c
new file mode 100644
index 000000000..99ccbb8c0
--- /dev/null
+++ b/src/map/clif.c
@@ -0,0 +1,9712 @@
+// $Id: clif.c 164 2004-10-01 16:46:58Z $
+
+#define DUMP_UNKNOWN_PACKET 1
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#ifdef _WIN32
+#include <winsock.h>
+#else
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#include <time.h>
+
+#include "socket.h"
+#include "timer.h"
+#include "malloc.h"
+#include "version.h"
+#include "nullpo.h"
+
+#include "map.h"
+#include "chrif.h"
+#include "clif.h"
+#include "pc.h"
+#include "npc.h"
+#include "itemdb.h"
+#include "chat.h"
+#include "trade.h"
+#include "storage.h"
+#include "script.h"
+#include "skill.h"
+#include "atcommand.h"
+#include "intif.h"
+#include "battle.h"
+#include "mob.h"
+#include "party.h"
+#include "guild.h"
+#include "vending.h"
+#include "pet.h"
+#include "mmo.h"
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+#define STATE_BLIND 0x10
+
+/* Packet Database */
+struct packet_db packet_db[MAX_PACKET_DB];
+
+// local define
+enum {
+ ALL_CLIENT,
+ ALL_SAMEMAP,
+ AREA,
+ AREA_WOS,
+ AREA_WOC,
+ AREA_WOSC,
+ AREA_CHAT_WOC,
+ CHAT,
+ CHAT_WOS,
+ PARTY,
+ PARTY_WOS,
+ PARTY_SAMEMAP,
+ PARTY_SAMEMAP_WOS,
+ PARTY_AREA,
+ PARTY_AREA_WOS,
+ GUILD,
+ GUILD_WOS,
+ GUILD_SAMEMAP, // [Valaris]
+ GUILD_SAMEMAP_WOS,
+ GUILD_AREA,
+ GUILD_AREA_WOS, // end additions [Valaris]
+ SELF
+};
+
+#define WBUFPOS(p,pos,x,y) { unsigned char *__p = (p); __p+=(pos); __p[0] = (x)>>2; __p[1] = ((x)<<6) | (((y)>>4)&0x3f); __p[2] = (y)<<4; }
+#define WBUFPOS2(p,pos,x0,y0,x1,y1) { unsigned char *__p = (p); __p+=(pos); __p[0] = (x0)>>2; __p[1] = ((x0)<<6) | (((y0)>>4)&0x3f); __p[2] = ((y0)<<4) | (((x1)>>6)&0x0f); __p[3]=((x1)<<2) | (((y1)>>8)&0x03); __p[4]=(y1); }
+
+#define WFIFOPOS(fd,pos,x,y) { WBUFPOS (WFIFOP(fd,pos),0,x,y); }
+#define WFIFOPOS2(fd,pos,x0,y0,x1,y1) { WBUFPOS2(WFIFOP(fd,pos),0,x0,y0,x1,y1); }
+
+static char map_ip_str[16];
+static in_addr_t map_ip;
+static int map_port = 5121;
+int map_fd;
+char talkie_mes[80];
+
+/*==========================================
+ * Clif Parsing Functions
+ *------------------------------------------
+ */
+void clif_parse_WantToConnection(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_LoadEndAck(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_TickSend(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_WalkToXY(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_QuitGame(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GetCharNameRequest(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GlobalMessage(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_MapMove(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_ChangeDir(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_Emotion(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_HowManyConnections(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_ActionRequest(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_Restart(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_Wis(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GMmessage(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_TakeItem(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_DropItem(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_UseItem(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_EquipItem(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_UnequipItem(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_NpcClicked(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_NpcBuySellSelected(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_NpcBuyListSend(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_NpcSellListSend(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_CreateChatRoom(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_ChatAddMember(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_ChatRoomStatusChange(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_ChangeChatOwner(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_KickFromChat(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_ChatLeave(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_TradeRequest(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_TradeAck(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_TradeAddItem(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_TradeOk(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_TradeCancel(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_TradeCommit(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_StopAttack(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_PutItemToCart(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GetItemFromCart(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_RemoveOption(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_ChangeCart(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_StatusUp(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_SkillUp(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_UseSkillToId(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_UseSkillToPos(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_UseSkillMap(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_RequestMemo(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_ProduceMix(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_NpcSelectMenu(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_NpcNextClicked(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_NpcAmountInput(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_NpcStringInput(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_NpcCloseClicked(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_ItemIdentify(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_SelectArrow(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_AutoSpell(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_UseCard(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_InsertCard(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_SolveCharName(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_ResetChar(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_LGMmessage(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_MoveToKafra(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_MoveFromKafra(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_MoveToKafraFromCart(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_MoveFromKafraToCart(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_CloseKafra(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_CreateParty(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_CreateParty2(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_PartyInvite(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_ReplyPartyInvite(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_LeaveParty(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_RemovePartyMember(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_PartyChangeOption(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_PartyMessage(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_CloseVending(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_VendingListReq(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_PurchaseReq(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_OpenVending(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_CreateGuild(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildCheckMaster(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildRequestInfo(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildChangePositionInfo(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildChangeMemberPosition(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildRequestEmblem(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildChangeEmblem(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildChangeNotice(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildInvite(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildReplyInvite(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildLeave(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildExplusion(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildMessage(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildRequestAlliance(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildReplyAlliance(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildDelAlliance(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildOpposition(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GuildBreak(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_PetMenu(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_CatchPet(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_SelectEgg(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_SendEmotion(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_ChangePetName(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GMKick(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GMHide(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GMReqNoChat(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GMReqNoChatCount(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_sn_doridori(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_sn_explosionspirits(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_wisexin(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_wisall(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_wisexlist(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GMkillall(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GMsummon(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_GMshift(int fd,struct map_session_data *sd, int cmd);
+void clif_parse_debug(int fd,struct map_session_data *sd, int cmd);
+
+struct {
+ void (*func)();
+ char *name;
+} clif_parse_func[]={
+ {clif_parse_WantToConnection,"wanttoconnection"},
+ {clif_parse_LoadEndAck,"loadendack"},
+ {clif_parse_TickSend,"ticksend"},
+ {clif_parse_WalkToXY,"walktoxy"},
+ {clif_parse_QuitGame,"quitgame"},
+ {clif_parse_GetCharNameRequest,"getcharnamerequest"},
+ {clif_parse_GlobalMessage,"globalmessage"},
+ {clif_parse_MapMove,"mapmove"},
+ {clif_parse_ChangeDir,"changedir"},
+ {clif_parse_Emotion,"emotion"},
+ {clif_parse_HowManyConnections,"howmanyconnections"},
+ {clif_parse_ActionRequest,"actionrequest"},
+ {clif_parse_Restart,"restart"},
+ {clif_parse_Wis,"wis"},
+ {clif_parse_GMmessage,"gmmessage"},
+ {clif_parse_TakeItem,"takeitem"},
+ {clif_parse_DropItem,"dropitem"},
+ {clif_parse_UseItem,"useitem"},
+ {clif_parse_EquipItem,"equipitem"},
+ {clif_parse_UnequipItem,"unequipitem"},
+ {clif_parse_NpcClicked,"npcclicked"},
+ {clif_parse_NpcBuySellSelected,"npcbuysellselected"},
+ {clif_parse_NpcBuyListSend,"npcbuylistsend"},
+ {clif_parse_NpcSellListSend,"npcselllistsend"},
+ {clif_parse_CreateChatRoom,"createchatroom"},
+ {clif_parse_ChatAddMember,"chataddmember"},
+ {clif_parse_ChatRoomStatusChange,"chatroomstatuschange"},
+ {clif_parse_ChangeChatOwner,"changechatowner"},
+ {clif_parse_KickFromChat,"kickfromchat"},
+ {clif_parse_ChatLeave,"chatleave"},
+ {clif_parse_TradeRequest,"traderequest"},
+ {clif_parse_TradeAck,"tradeack"},
+ {clif_parse_TradeAddItem,"tradeadditem"},
+ {clif_parse_TradeOk,"tradeok"},
+ {clif_parse_TradeCancel,"tradecancel"},
+ {clif_parse_TradeCommit,"tradecommit"},
+ {clif_parse_StopAttack,"stopattack"},
+ {clif_parse_PutItemToCart,"putitemtocart"},
+ {clif_parse_GetItemFromCart,"getitemfromcart"},
+ {clif_parse_RemoveOption,"removeoption"},
+ {clif_parse_ChangeCart,"changecart"},
+ {clif_parse_StatusUp,"statusup"},
+ {clif_parse_SkillUp,"skillup"},
+ {clif_parse_UseSkillToId,"useskilltoid"},
+ {clif_parse_UseSkillToPos,"useskilltopos"},
+ {clif_parse_UseSkillMap,"useskillmap"},
+ {clif_parse_RequestMemo,"requestmemo"},
+ {clif_parse_ProduceMix,"producemix"},
+ {clif_parse_NpcSelectMenu,"npcselectmenu"},
+ {clif_parse_NpcNextClicked,"npcnextclicked"},
+ {clif_parse_NpcAmountInput,"npcamountinput"},
+ {clif_parse_NpcStringInput,"npcstringinput"},
+ {clif_parse_NpcCloseClicked,"npccloseclicked"},
+ {clif_parse_ItemIdentify,"itemidentify"},
+ {clif_parse_SelectArrow,"selectarrow"},
+ {clif_parse_AutoSpell,"autospell"},
+ {clif_parse_UseCard,"usecard"},
+ {clif_parse_InsertCard,"insertcard"},
+ {clif_parse_SolveCharName,"solvecharname"},
+ {clif_parse_ResetChar,"resetchar"},
+ {clif_parse_LGMmessage,"lgmmessage"},
+ {clif_parse_MoveToKafra,"movetokafra"},
+ {clif_parse_MoveFromKafra,"movefromkafra"},
+ {clif_parse_MoveToKafraFromCart,"movetokafrafromcart"},
+ {clif_parse_MoveFromKafraToCart,"movefromkafratocart"},
+ {clif_parse_CloseKafra,"closekafra"},
+ {clif_parse_CreateParty,"createparty"},
+ {clif_parse_CreateParty2,"createparty2"},
+ {clif_parse_PartyInvite,"partyinvite"},
+ {clif_parse_ReplyPartyInvite,"replypartyinvite"},
+ {clif_parse_LeaveParty,"leaveparty"},
+ {clif_parse_RemovePartyMember,"removepartymember"},
+ {clif_parse_PartyChangeOption,"partychangeoption"},
+ {clif_parse_PartyMessage,"partymessage"},
+ {clif_parse_CloseVending,"closevending"},
+ {clif_parse_VendingListReq,"vendinglistreq"},
+ {clif_parse_PurchaseReq,"purchasereq"},
+ {clif_parse_OpenVending,"openvending"},
+ {clif_parse_CreateGuild,"createguild"},
+ {clif_parse_GuildCheckMaster,"guildcheckmaster"},
+ {clif_parse_GuildRequestInfo,"guildrequestinfo"},
+ {clif_parse_GuildChangePositionInfo,"guildchangepositioninfo"},
+ {clif_parse_GuildChangeMemberPosition,"guildchangememberposition"},
+ {clif_parse_GuildRequestEmblem,"guildrequestemblem"},
+ {clif_parse_GuildChangeEmblem,"guildchangeemblem"},
+ {clif_parse_GuildChangeNotice,"guildchangenotice"},
+ {clif_parse_GuildInvite,"guildinvite"},
+ {clif_parse_GuildReplyInvite,"guildreplyinvite"},
+ {clif_parse_GuildLeave,"guildleave"},
+ {clif_parse_GuildExplusion,"guildexplusion"},
+ {clif_parse_GuildMessage,"guildmessage"},
+ {clif_parse_GuildRequestAlliance,"guildrequestalliance"},
+ {clif_parse_GuildReplyAlliance,"guildreplyalliance"},
+ {clif_parse_GuildDelAlliance,"guilddelalliance"},
+ {clif_parse_GuildOpposition,"guildopposition"},
+ {clif_parse_GuildBreak,"guildbreak"},
+ {clif_parse_PetMenu,"petmenu"},
+ {clif_parse_CatchPet,"catchpet"},
+ {clif_parse_SelectEgg,"selectegg"},
+ {clif_parse_SendEmotion,"sendemotion"},
+ {clif_parse_ChangePetName,"changepetname"},
+ {clif_parse_GMKick,"gmkick"},
+ {clif_parse_GMHide,"gmhide"},
+ {clif_parse_GMReqNoChat,"gmreqnochat"},
+ {clif_parse_GMReqNoChatCount,"gmreqnochatcount"},
+ {clif_parse_sn_doridori,"sndoridori"},
+ {clif_parse_sn_explosionspirits,"snexplosionspirits"},
+ {clif_parse_wisexin,"wisexin"},
+ {clif_parse_wisexlist,"wisexlist"},
+ {clif_parse_wisall,"wisall"},
+ {clif_parse_GMkillall,"killall"},
+ {clif_parse_GMsummon,"summon"},
+ {clif_parse_GMshift,"shift"},
+ {clif_parse_debug,"debug"},
+
+ {NULL,NULL}
+};
+
+/*==========================================
+ * map鯖のip設定
+ *------------------------------------------
+ */
+void clif_setip(char *ip)
+{
+ memcpy(map_ip_str, ip, 16);
+ map_ip = inet_addr(map_ip_str);
+}
+
+/*==========================================
+ * map鯖のport設定
+ *------------------------------------------
+ */
+void clif_setport(int port)
+{
+ map_port = port;
+}
+
+/*==========================================
+ * map鯖のip読み出し
+ *------------------------------------------
+ */
+in_addr_t clif_getip(void)
+{
+ return map_ip;
+}
+
+/*==========================================
+ * map鯖のport読み出し
+ *------------------------------------------
+ */
+int clif_getport(void)
+{
+ return map_port;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_countusers(void)
+{
+ int users = 0, i;
+ struct map_session_data *sd;
+
+ for(i = 0; i < fd_max; i++) {
+ if (session[i] && (sd = session[i]->session_data) && sd && sd->state.auth &&
+ !(battle_config.hide_GM_session && pc_isGM(sd)))
+ users++;
+ }
+ return users;
+}
+
+/*==========================================
+ * 全てのclientに対してfunc()実行
+ *------------------------------------------
+ */
+int clif_foreachclient(int (*func)(struct map_session_data*, va_list),...)
+{
+ int i;
+ va_list ap;
+ struct map_session_data *sd;
+
+ va_start(ap,func);
+ for(i = 0; i < fd_max; i++) {
+ if (session[i] && (sd = session[i]->session_data) && sd && sd->state.auth)
+ func(sd, ap);
+ }
+ va_end(ap);
+ return 0;
+}
+
+/*==========================================
+ * clif_sendでAREA*指定時用
+ *------------------------------------------
+ */
+int clif_send_sub(struct block_list *bl, va_list ap)
+{
+ unsigned char *buf;
+ int len;
+ struct block_list *src_bl;
+ int type;
+ struct map_session_data *sd;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, sd = (struct map_session_data *)bl);
+
+ buf = va_arg(ap,unsigned char*);
+ len = va_arg(ap,int);
+ nullpo_retr(0, src_bl = va_arg(ap,struct block_list*));
+ type = va_arg(ap,int);
+
+ switch(type) {
+ case AREA_WOS:
+ if (bl && bl == src_bl)
+ return 0;
+ break;
+ case AREA_WOC:
+ if ((sd && sd->chatID) || (bl && bl == src_bl))
+ return 0;
+ break;
+ case AREA_WOSC:
+ if ((sd) && sd->chatID && sd->chatID == ((struct map_session_data*)src_bl)->chatID)
+ return 0;
+ break;
+ }
+
+ if (sd) {
+ if (WFIFOP(sd->fd,0) == buf) {
+ printf("WARNING: Invalid use of clif_send function\n");
+ printf(" Packet x%4x use a WFIFO of a player instead of to use a buffer.\n", WBUFW(buf,0));
+ printf(" Please correct your code.\n");
+ // don't send to not move the pointer of the packet for next sessions in the loop
+ } else {
+ memcpy(WFIFOP(sd->fd,0), buf, len);
+ WFIFOSET(sd->fd,len);
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_send(unsigned char *buf, int len, struct block_list *bl, int type) {
+ int i;
+ struct map_session_data *sd;
+ struct chat_data *cd;
+ struct party *p = NULL;
+ struct guild *g = NULL;
+ int x0 = 0, x1 = 0, y0 = 0, y1 = 0;
+
+ if (type != ALL_CLIENT) {
+ nullpo_retr(0, bl);
+ }
+
+ switch(type) {
+ case ALL_CLIENT: // 全クライアントに送信
+ for(i = 0; i < fd_max; i++) {
+ if (session[i] && (sd = session[i]->session_data) != NULL && sd->state.auth) {
+ memcpy(WFIFOP(i,0), buf, len);
+ WFIFOSET(i,len);
+ }
+ }
+ break;
+ case ALL_SAMEMAP: // 同じマップの全クライアントに送信
+ for(i = 0; i < fd_max; i++) {
+ if (session[i] && (sd = session[i]->session_data) != NULL && sd->state.auth && sd->bl.m == bl->m) {
+ memcpy(WFIFOP(i,0), buf, len);
+ WFIFOSET(i,len);
+ }
+ }
+ break;
+ case AREA:
+ case AREA_WOS:
+ case AREA_WOC:
+ case AREA_WOSC:
+ map_foreachinarea(clif_send_sub, bl->m, bl->x-AREA_SIZE, bl->y-AREA_SIZE, bl->x+AREA_SIZE, bl->y+AREA_SIZE, BL_PC, buf, len, bl, type);
+ break;
+ case AREA_CHAT_WOC:
+ map_foreachinarea(clif_send_sub, bl->m, bl->x-(AREA_SIZE-5), bl->y-(AREA_SIZE-5), bl->x+(AREA_SIZE-5), bl->y+(AREA_SIZE-5), BL_PC, buf, len, bl, AREA_WOC);
+ break;
+ case CHAT:
+ case CHAT_WOS:
+ cd = (struct chat_data*)bl;
+ if (bl->type == BL_PC) {
+ sd = (struct map_session_data*)bl;
+ cd = (struct chat_data*)map_id2bl(sd->chatID);
+ } else if (bl->type != BL_CHAT)
+ break;
+ if (cd == NULL)
+ break;
+ for(i = 0; i < cd->users; i++) {
+ if (type == CHAT_WOS && cd->usersd[i] == (struct map_session_data*)bl)
+ continue;
+ memcpy(WFIFOP(cd->usersd[i]->fd,0), buf, len);
+ WFIFOSET(cd->usersd[i]->fd,len);
+ }
+ break;
+
+ case PARTY_AREA: // 同じ画面内の全パーティーメンバに送信
+ case PARTY_AREA_WOS: // 自分以外の同じ画面内の全パーティーメンバに送信
+ x0 = bl->x - AREA_SIZE;
+ y0 = bl->y - AREA_SIZE;
+ x1 = bl->x + AREA_SIZE;
+ y1 = bl->y + AREA_SIZE;
+ case PARTY: // 全パーティーメンバに送信
+ case PARTY_WOS: // 自分以外の全パーティーメンバに送信
+ case PARTY_SAMEMAP: // 同じマップの全パーティーメンバに送信
+ case PARTY_SAMEMAP_WOS: // 自分以外の同じマップの全パーティーメンバに送信
+ if (bl->type == BL_PC) {
+ sd = (struct map_session_data *)bl;
+ if (sd->partyspy > 0) {
+ p = party_search(sd->partyspy);
+ } else {
+ if (sd->status.party_id > 0)
+ p = party_search(sd->status.party_id);
+ }
+ }
+ if (p) {
+ for(i=0;i<MAX_PARTY;i++){
+ if ((sd = p->member[i].sd) != NULL) {
+ if (sd->bl.id == bl->id && (type == PARTY_WOS ||
+ type == PARTY_SAMEMAP_WOS || type == PARTY_AREA_WOS))
+ continue;
+ if (type != PARTY && type != PARTY_WOS && bl->m != sd->bl.m) // マップチェック
+ continue;
+ if ((type == PARTY_AREA || type == PARTY_AREA_WOS) &&
+ (sd->bl.x < x0 || sd->bl.y < y0 ||
+ sd->bl.x > x1 || sd->bl.y > y1))
+ continue;
+ memcpy(WFIFOP(sd->fd,0), buf, len);
+ WFIFOSET(sd->fd,len);
+// if(battle_config.etc_log)
+// printf("send party %d %d %d\n",p->party_id,i,flag)
+
+ }
+ }
+ for (i = 0; i < fd_max; i++){
+ if (session[i] && (sd = session[i]->session_data) != NULL && sd->state.auth) {
+ if (sd->partyspy == p->party_id) {
+ memcpy(WFIFOP(sd->fd,0), buf, len);
+ WFIFOSET(sd->fd,len);
+ }
+ }
+ }
+ }
+ break;
+ case SELF:
+ sd = (struct map_session_data *)bl;
+ memcpy(WFIFOP(sd->fd,0), buf, len);
+ WFIFOSET(sd->fd,len);
+ break;
+
+/* New definitions for guilds [Valaris] */
+
+ case GUILD_AREA:
+ case GUILD_AREA_WOS:
+ x0 = bl->x - AREA_SIZE;
+ y0 = bl->y - AREA_SIZE;
+ x1 = bl->x + AREA_SIZE;
+ y1 = bl->y + AREA_SIZE;
+ case GUILD:
+ case GUILD_WOS:
+ if (bl && bl->type == BL_PC) { // guildspy [Syrus22]
+ sd = (struct map_session_data *)bl;
+ if (sd->guildspy > 0) {
+ g = guild_search(sd->guildspy);
+ } else {
+ if (sd->status.guild_id > 0)
+ g = guild_search(sd->status.guild_id);
+ }
+ }
+ if (g) {
+ for(i = 0; i < g->max_member; i++) {
+ if ((sd = g->member[i].sd) != NULL) {
+ if (type == GUILD_WOS && sd->bl.id == bl->id)
+ continue;
+ memcpy(WFIFOP(sd->fd,0), buf, len);
+ WFIFOSET(sd->fd,len);
+ }
+ }
+ for (i = 0; i < fd_max; i++){
+ if (session[i] && (sd = session[i]->session_data) != NULL && sd->state.auth) {
+ if (sd->guildspy == g->guild_id) {
+ memcpy(WFIFOP(sd->fd,0), buf, len);
+ WFIFOSET(sd->fd,len);
+ }
+ }
+ }
+ }
+ break;
+ case GUILD_SAMEMAP:
+ case GUILD_SAMEMAP_WOS:
+ if (bl->type == BL_PC) {
+ sd = (struct map_session_data *)bl;
+ if (sd->status.guild_id > 0)
+ g = guild_search(sd->status.guild_id);
+ }
+ if (g) {
+ for(i = 0; i < g->max_member; i++) {
+ if ((sd = g->member[i].sd) != NULL) {
+ if (sd->bl.id == bl->id && (type == GUILD_WOS ||
+ type == GUILD_SAMEMAP_WOS || type == GUILD_AREA_WOS))
+ continue;
+ if (type != GUILD && type != GUILD_WOS && bl->m != sd->bl.m) // マップチェック
+ continue;
+ if ((type == GUILD_AREA || type == GUILD_AREA_WOS) &&
+ (sd->bl.x < x0 || sd->bl.y < y0 ||
+ sd->bl.x > x1 || sd->bl.y > y1))
+ continue;
+ memcpy(WFIFOP(sd->fd,0), buf, len);
+ WFIFOSET(sd->fd,len);
+ }
+ }
+ }
+ break;
+/* End [Valaris] */
+
+ default:
+ if (battle_config.error_log)
+ printf("clif_send まだ作ってないよー\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+//
+// パケット作って送信
+//
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_authok(struct map_session_data *sd) {
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ if (!sd)
+ return 0;
+
+ if (!sd->fd)
+ return 0;
+
+ fd = sd->fd;
+
+ WFIFOW(fd, 0) = 0x73;
+ WFIFOL(fd, 2) = gettick();
+ WFIFOPOS(fd, 6, sd->bl.x, sd->bl.y);
+ WFIFOB(fd, 9) = 5;
+ WFIFOB(fd,10) = 5;
+ WFIFOSET(fd,packet_db[0x73].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_authfail_fd(int fd, int type) {
+ if (!fd || !session[fd])
+ return 0;
+
+ WFIFOW(fd,0) = 0x81;
+ WFIFOL(fd,2) = type;
+ WFIFOSET(fd,packet_db[0x81].len);
+
+ clif_setwaitclose(fd);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_charselectok(int id) {
+ struct map_session_data *sd;
+ int fd;
+
+ if ((sd = map_id2sd(id)) == NULL)
+ return 1;
+
+ if (!sd->fd)
+ return 1;
+
+ fd = sd->fd;
+ WFIFOW(fd,0) = 0xb3;
+ WFIFOB(fd,2) = 1;
+ WFIFOSET(fd,packet_db[0xb3].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static int clif_set009e(struct flooritem_data *fitem,unsigned char *buf) {
+ int view;
+
+ nullpo_retr(0, fitem);
+
+ //009e <ID>.l <name ID>.w <identify flag>.B <X>.w <Y>.w <subX>.B <subY>.B <amount>.w
+ WBUFW(buf, 0) = 0x9e;
+ WBUFL(buf, 2) = fitem->bl.id;
+ if ((view = itemdb_viewid(fitem->item_data.nameid)) > 0)
+ WBUFW(buf, 6) = view;
+ else
+ WBUFW(buf, 6) = fitem->item_data.nameid;
+ WBUFB(buf, 8) = fitem->item_data.identify;
+ WBUFW(buf, 9) = fitem->bl.x;
+ WBUFW(buf,11) = fitem->bl.y;
+ WBUFB(buf,13) = fitem->subx;
+ WBUFB(buf,14) = fitem->suby;
+ WBUFW(buf,15) = fitem->item_data.amount;
+
+ return packet_db[0x9e].len;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_dropflooritem(struct flooritem_data *fitem) {
+ char buf[64];
+
+ nullpo_retr(0, fitem);
+
+ if (fitem->item_data.nameid <= 0)
+ return 0;
+ clif_set009e(fitem, buf);
+ clif_send(buf, packet_db[0x9e].len, &fitem->bl, AREA);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_clearflooritem(struct flooritem_data *fitem, int fd) {
+ unsigned char buf[16];
+
+ nullpo_retr(0, fitem);
+
+ WBUFW(buf,0) = 0xa1;
+ WBUFL(buf,2) = fitem->bl.id;
+
+ if (fd == 0) {
+ clif_send(buf, packet_db[0xa1].len, &fitem->bl, AREA);
+ } else {
+ memcpy(WFIFOP(fd,0), buf, 6);
+ WFIFOSET(fd,packet_db[0xa1].len);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_clearchar(struct block_list *bl, int type) {
+ unsigned char buf[16];
+
+ nullpo_retr(0, bl);
+
+ WBUFW(buf,0) = 0x80;
+ WBUFL(buf,2) = bl->id;
+ if (type == 9) {
+ WBUFB(buf,6) = 0;
+ clif_send(buf, packet_db[0x80].len, bl, AREA);
+ } else {
+ WBUFB(buf,6) = type;
+ clif_send(buf, packet_db[0x80].len, bl, type == 1 ? AREA : AREA_WOS);
+ }
+
+ return 0;
+}
+
+static int clif_clearchar_delay_sub(int tid, unsigned int tick, int id, int data) {
+ struct block_list *bl = (struct block_list *)id;
+
+ clif_clearchar(bl,data);
+ map_freeblock(bl);
+
+ return 0;
+}
+
+int clif_clearchar_delay(unsigned int tick, struct block_list *bl, int type) {
+ struct block_list *tmpbl = calloc(sizeof(struct block_list), 1);
+ if (tmpbl == NULL) {
+ printf("clif_clearchar_delay: out of memory !\n");
+ exit(1);
+ }
+ memcpy(tmpbl, bl, sizeof(struct block_list));
+ add_timer(tick, clif_clearchar_delay_sub, (int)tmpbl, type);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_clearchar_id(int id, int type, int fd) {
+ unsigned char buf[16];
+
+ WBUFW(buf,0) = 0x80;
+ WBUFL(buf,2) = id;
+ WBUFB(buf,6) = type;
+ memcpy(WFIFOP(fd,0), buf, 7);
+ WFIFOSET(fd, packet_db[0x80].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static int clif_set0078(struct map_session_data *sd, unsigned char *buf) {
+ int level=0;
+
+ nullpo_retr(0, sd);
+
+ if (sd->disguise > 23 && sd->disguise < 4001) { // mob disguises [Valaris]
+ WBUFW(buf,0) = 0x78;
+ WBUFL(buf,2) = sd->bl.id;
+ WBUFW(buf,6) = battle_get_speed(&sd->bl);
+ WBUFW(buf,8) = sd->opt1;
+ WBUFW(buf,10) = sd->opt2;
+ WBUFW(buf,12) = sd->status.option;
+ WBUFW(buf,14) = sd->disguise;
+ WBUFW(buf,42) = 0;
+ WBUFB(buf,44) = 0;
+ WBUFPOS(buf, 46, sd->bl.x, sd->bl.y);
+ WBUFB(buf,48) |= sd->dir & 0x0f;
+ WBUFB(buf,49) = 5;
+ WBUFB(buf,50) = 5;
+ WBUFB(buf,51) = 0;
+ WBUFW(buf,52) = ((level = battle_get_lv(&sd->bl)) > battle_config.max_lv) ? battle_config.max_lv : level;
+
+ return packet_db[0x78].len;
+ }
+
+#if PACKETVER < 4
+ WBUFW(buf,0)= 0x78;
+ WBUFL(buf,2)= sd->bl.id;
+ WBUFW(buf,6)= sd->speed;
+ WBUFW(buf,8)= sd->opt1;
+ WBUFW(buf,10)= sd->opt2;
+ WBUFW(buf,12)= sd->status.option;
+ WBUFW(buf,14)= sd->view_class;
+ WBUFW(buf,16)= sd->status.hair;
+ if (sd->view_class != 22)
+ WBUFW(buf,18) = sd->status.weapon;
+ else
+ WBUFW(buf,18)=0;
+ WBUFW(buf,20)=sd->status.head_bottom;
+ WBUFW(buf,22)=sd->status.shield;
+ WBUFW(buf,24)=sd->status.head_top;
+ WBUFW(buf,26)=sd->status.head_mid;
+ WBUFW(buf,28)=sd->status.hair_color;
+ WBUFW(buf,30)=sd->status.clothes_color;
+ WBUFW(buf,32)=sd->head_dir;
+ WBUFL(buf,34)=sd->status.guild_id;
+ WBUFL(buf,38)=sd->guild_emblem_id;
+ WBUFW(buf,42)=sd->status.manner;
+ WBUFB(buf,44)=sd->status.karma;
+ WBUFB(buf,45)=sd->sex;
+ WBUFPOS(buf,46,sd->bl.x,sd->bl.y);
+ WBUFB(buf,48)|=sd->dir&0x0f;
+ WBUFB(buf,49)=5;
+ WBUFB(buf,50)=5;
+ WBUFB(buf,51)=sd->state.dead_sit;
+ WBUFW(buf,52)=(sd->status.base_level>battle_config.max_lv)?battle_config.max_lv:sd->status.base_level;
+
+ return packet_db[0x78].len;
+#else
+ WBUFW(buf,0) = 0x1d8;
+ WBUFL(buf,2) = sd->bl.id;
+ WBUFW(buf,6) = sd->speed;
+ WBUFW(buf,8) = sd->opt1;
+ WBUFW(buf,10) = sd->opt2;
+ WBUFW(buf,12) = sd->status.option;
+ WBUFW(buf,14) = sd->view_class;
+ WBUFW(buf,16) = sd->status.hair;
+ if (sd->equip_index[9] >= 0 && sd->inventory_data[sd->equip_index[9]] && sd->view_class != 22) {
+ if (sd->inventory_data[sd->equip_index[9]]->view_id > 0)
+ WBUFW(buf,18) = sd->inventory_data[sd->equip_index[9]]->view_id;
+ else
+ WBUFW(buf,18) = sd->status.inventory[sd->equip_index[9]].nameid;
+ } else
+ WBUFW(buf,18) = 0;
+ if (sd->equip_index[8] >= 0 && sd->equip_index[8] != sd->equip_index[9] && sd->inventory_data[sd->equip_index[8]] && sd->view_class != 22) {
+ if (sd->inventory_data[sd->equip_index[8]]->view_id > 0)
+ WBUFW(buf,20) = sd->inventory_data[sd->equip_index[8]]->view_id;
+ else
+ WBUFW(buf,20) = sd->status.inventory[sd->equip_index[8]].nameid;
+ } else
+ WBUFW(buf,20) = 0;
+ WBUFW(buf,22)=sd->status.head_bottom;
+ WBUFW(buf,24)=sd->status.head_top;
+ WBUFW(buf,26)=sd->status.head_mid;
+ WBUFW(buf,28)=sd->status.hair_color;
+ WBUFW(buf,30)=sd->status.clothes_color;
+ WBUFW(buf,32)=sd->head_dir;
+ WBUFL(buf,34)=sd->status.guild_id;
+ WBUFW(buf,38)=sd->guild_emblem_id;
+ WBUFW(buf,40)=sd->status.manner;
+ WBUFW(buf,42)=sd->opt3;
+ WBUFB(buf,44)=sd->status.karma;
+ WBUFB(buf,45)=sd->sex;
+ WBUFPOS(buf,46,sd->bl.x,sd->bl.y);
+ WBUFB(buf,48)|=sd->dir&0x0f;
+ WBUFB(buf,49)=5;
+ WBUFB(buf,50)=5;
+ WBUFB(buf,51)=sd->state.dead_sit;
+ WBUFW(buf,52)=((level = battle_get_lv(&sd->bl)) > battle_config.max_lv) ? battle_config.max_lv : level;
+
+ return packet_db[0x1d8].len;
+#endif
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static int clif_set007b(struct map_session_data *sd,unsigned char *buf) {
+ int level=0;
+
+ nullpo_retr(0, sd);
+
+ if (sd->disguise > 23 && sd->disguise < 4001) { // mob disguises [Valaris]
+ WBUFW(buf,0)=0x7b;
+ WBUFL(buf,2)=sd->bl.id;
+ WBUFW(buf,6)=battle_get_speed(&sd->bl);
+ WBUFW(buf,8)=sd->opt1;
+ WBUFW(buf,10)=sd->opt2;
+ WBUFW(buf,12)=sd->status.option;
+ WBUFW(buf,14)=sd->disguise;
+ WBUFL(buf,22)=gettick();
+ WBUFW(buf,46)=0;
+ WBUFB(buf,48)=0;
+ WBUFPOS2(buf,50,sd->bl.x,sd->bl.y,sd->to_x,sd->to_y);
+ WBUFB(buf,55)=0;
+ WBUFB(buf,56)=5;
+ WBUFB(buf,57)=5;
+ WBUFW(buf,58)=((level = battle_get_lv(&sd->bl))>battle_config.max_lv)? battle_config.max_lv:level;
+
+ return packet_db[0x7b].len;
+ }
+
+#if PACKETVER < 4
+ WBUFW(buf,0)=0x7b;
+ WBUFL(buf,2)=sd->bl.id;
+ WBUFW(buf,6)=sd->speed;
+ WBUFW(buf,8)=sd->opt1;
+ WBUFW(buf,10)=sd->opt2;
+ WBUFW(buf,12)=sd->status.option;
+ WBUFW(buf,14)=sd->view_class;
+ WBUFW(buf,16)=sd->status.hair;
+ if(sd->view_class != 22)
+ WBUFW(buf,18)=sd->status.weapon;
+ else
+ WBUFW(buf,18)=0;
+ WBUFW(buf,20)=sd->status.head_bottom;
+ WBUFL(buf,22)=gettick();
+ WBUFW(buf,26)=sd->status.shield;
+ WBUFW(buf,28)=sd->status.head_top;
+ WBUFW(buf,30)=sd->status.head_mid;
+ WBUFW(buf,32)=sd->status.hair_color;
+ WBUFW(buf,34)=sd->status.clothes_color;
+ WBUFW(buf,36)=sd->head_dir;
+ WBUFL(buf,38)=sd->status.guild_id;
+ WBUFL(buf,42)=sd->guild_emblem_id;
+ WBUFW(buf,46)=sd->status.manner;
+ WBUFB(buf,48)=sd->status.karma;
+ WBUFB(buf,49)=sd->sex;
+ WBUFPOS2(buf,50,sd->bl.x,sd->bl.y,sd->to_x,sd->to_y);
+ WBUFB(buf,55)=0;
+ WBUFB(buf,56)=5;
+ WBUFB(buf,57)=5;
+ WBUFW(buf,58)=(sd->status.base_level>battle_config.max_lv)?battle_config.max_lv:sd->status.base_level;
+
+ return packet_db[0x7b].len;
+#else
+ WBUFW(buf,0)=0x1da;
+ WBUFL(buf,2)=sd->bl.id;
+ WBUFW(buf,6)=sd->speed;
+ WBUFW(buf,8)=sd->opt1;
+ WBUFW(buf,10)=sd->opt2;
+ WBUFW(buf,12)=sd->status.option;
+ WBUFW(buf,14)=sd->view_class;
+ WBUFW(buf,16)=sd->status.hair;
+ if(sd->equip_index[9] >= 0 && sd->inventory_data[sd->equip_index[9]] && sd->view_class != 22) {
+ if(sd->inventory_data[sd->equip_index[9]]->view_id > 0)
+ WBUFW(buf,18)=sd->inventory_data[sd->equip_index[9]]->view_id;
+ else
+ WBUFW(buf,18)=sd->status.inventory[sd->equip_index[9]].nameid;
+ }
+ else
+ WBUFW(buf,18)=0;
+ if(sd->equip_index[8] >= 0 && sd->equip_index[8] != sd->equip_index[9] && sd->inventory_data[sd->equip_index[8]] && sd->view_class != 22) {
+ if(sd->inventory_data[sd->equip_index[8]]->view_id > 0)
+ WBUFW(buf,20)=sd->inventory_data[sd->equip_index[8]]->view_id;
+ else
+ WBUFW(buf,20)=sd->status.inventory[sd->equip_index[8]].nameid;
+ }
+ else
+ WBUFW(buf,20)=0;
+ WBUFW(buf,22)=sd->status.head_bottom;
+ WBUFL(buf,24)=gettick();
+ WBUFW(buf,28)=sd->status.head_top;
+ WBUFW(buf,30)=sd->status.head_mid;
+ WBUFW(buf,32)=sd->status.hair_color;
+ WBUFW(buf,34)=sd->status.clothes_color;
+ WBUFW(buf,36)=sd->head_dir;
+ WBUFL(buf,38)=sd->status.guild_id;
+ WBUFW(buf,42)=sd->guild_emblem_id;
+ WBUFW(buf,44)=sd->status.manner;
+ WBUFW(buf,46)=sd->opt3;
+ WBUFB(buf,48)=sd->status.karma;
+ WBUFB(buf,49)=sd->sex;
+ WBUFPOS2(buf,50,sd->bl.x,sd->bl.y,sd->to_x,sd->to_y);
+ WBUFB(buf,55)=0;
+ WBUFB(buf,56)=5;
+ WBUFB(buf,57)=5;
+ WBUFW(buf,58)=(sd->status.base_level>battle_config.max_lv)?battle_config.max_lv:sd->status.base_level;
+
+ return packet_db[0x1da].len;
+#endif
+}
+
+/*==========================================
+ * クラスチェンジ typeはMobの場合は1で他は0?
+ *------------------------------------------
+ */
+int clif_class_change(struct block_list *bl,int class,int type)
+{
+ char buf[16];
+
+ nullpo_retr(0, bl);
+
+ if(class >= MAX_PC_CLASS) {
+ WBUFW(buf,0)=0x1b0;
+ WBUFL(buf,2)=bl->id;
+ WBUFB(buf,6)=type;
+ WBUFL(buf,7)=class;
+
+ clif_send(buf,packet_db[0x1b0].len,bl,AREA);
+ }
+ return 0;
+}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_mob_class_change(struct mob_data *md, int class) {
+ char buf[16];
+ int view = mob_get_viewclass(class);
+
+ nullpo_retr(0, md);
+
+ if(view >= MAX_PC_CLASS) {
+ WBUFW(buf,0)=0x1b0;
+ WBUFL(buf,2)=md->bl.id;
+ WBUFB(buf,6)=1;
+ WBUFL(buf,7)=view;
+
+ clif_send(buf,packet_db[0x1b0].len,&md->bl,AREA);
+ }
+ return 0;
+}
+// mob equipment [Valaris]
+
+int clif_mob_equip(struct mob_data *md, int nameid) {
+ unsigned char buf[16];
+
+ nullpo_retr(0, md);
+
+ memset(buf,0,packet_db[0x1a4].len);
+
+ WBUFW(buf,0)=0x1a4;
+ WBUFB(buf,2)=3;
+ WBUFL(buf,3)=md->bl.id;
+ WBUFL(buf,7)=nameid;
+
+ clif_send(buf,packet_db[0x1a4].len,&md->bl,AREA);
+
+ return 0;
+}
+
+/*==========================================
+ * MOB表示1
+ *------------------------------------------
+ */
+static int clif_mob0078(struct mob_data *md, unsigned char *buf)
+{
+ int level;
+
+ memset(buf,0,packet_db[0x78].len);
+
+ nullpo_retr(0, md);
+
+ WBUFW(buf,0)=0x78;
+ WBUFL(buf,2)=md->bl.id;
+ WBUFW(buf,6)=battle_get_speed(&md->bl);
+ WBUFW(buf,8)=md->opt1;
+ WBUFW(buf,10)=md->opt2;
+ WBUFW(buf,12)=md->option;
+ WBUFW(buf,14)=mob_get_viewclass(md->class);
+ if((mob_get_viewclass(md->class) <= 23) || (mob_get_viewclass(md->class) == 812) || (mob_get_viewclass(md->class) >= 4001)) {
+ WBUFW(buf,12)|=mob_db[md->class].option;
+ WBUFW(buf,16)=mob_get_hair(md->class);
+ WBUFW(buf,18)=mob_get_weapon(md->class);
+ WBUFW(buf,20)=mob_get_head_buttom(md->class);
+ WBUFW(buf,22)=mob_get_shield(md->class);
+ WBUFW(buf,24)=mob_get_head_top(md->class);
+ WBUFW(buf,26)=mob_get_head_mid(md->class);
+ WBUFW(buf,28)=mob_get_hair_color(md->class);
+ WBUFW(buf,30)=mob_get_clothes_color(md->class); //Add for player monster dye - Valaris
+ WBUFB(buf,45)=mob_get_sex(md->class);
+ }
+
+ if (md->class >= 1285 && md->class <= 1287) { // Added guardian emblems [Valaris]
+ struct guild *g;
+ struct guild_castle *gc=guild_mapname2gc(map[md->bl.m].name);
+ if (gc && gc->guild_id > 0) {
+ g=guild_search(gc->guild_id);
+ if (g) {
+ WBUFL(buf,26)=gc->guild_id;
+ WBUFL(buf,22)=g->emblem_id;
+ }
+ }
+ } // End addition
+
+ WBUFPOS(buf,46,md->bl.x,md->bl.y);
+ WBUFB(buf,48)|=md->dir&0x0f;
+ WBUFB(buf,49)=5;
+ WBUFB(buf,50)=5;
+ WBUFW(buf,52)=((level = battle_get_lv(&md->bl))>battle_config.max_lv)? battle_config.max_lv:level;
+
+ return packet_db[0x78].len;
+}
+
+/*==========================================
+ * MOB表示2
+ *------------------------------------------
+ */
+static int clif_mob007b(struct mob_data *md, unsigned char *buf) {
+ int level;
+
+ memset(buf,0,packet_db[0x7b].len);
+
+ nullpo_retr(0, md);
+
+ WBUFW(buf,0)=0x7b;
+ WBUFL(buf,2)=md->bl.id;
+ WBUFW(buf,6)=battle_get_speed(&md->bl);
+ WBUFW(buf,8)=md->opt1;
+ WBUFW(buf,10)=md->opt2;
+ WBUFW(buf,12)=md->option;
+ WBUFW(buf,14)=mob_get_viewclass(md->class);
+ if ((mob_get_viewclass(md->class) < 24) || (mob_get_viewclass(md->class) > 4000)) {
+ WBUFW(buf,12)|=mob_db[md->class].option;
+ WBUFW(buf,16)=mob_get_hair(md->class);
+ WBUFW(buf,18)=mob_get_weapon(md->class);
+ WBUFW(buf,20)=mob_get_head_buttom(md->class);
+ WBUFL(buf,22)=gettick();
+ WBUFW(buf,26)=mob_get_shield(md->class);
+ WBUFW(buf,28)=mob_get_head_top(md->class);
+ WBUFW(buf,30)=mob_get_head_mid(md->class);
+ WBUFW(buf,32)=mob_get_hair_color(md->class);
+ WBUFW(buf,34)=mob_get_clothes_color(md->class); //Add for player monster dye - Valaris
+ WBUFB(buf,49)=mob_get_sex(md->class);
+ } else
+ WBUFL(buf,22)=gettick();
+
+ if(md->class >= 1285 && md->class <= 1287) { // Added guardian emblems [Valaris]
+ struct guild *g;
+ struct guild_castle *gc=guild_mapname2gc(map[md->bl.m].name);
+ if(gc && gc->guild_id > 0){
+ g=guild_search(gc->guild_id);
+ if(g) {
+ WBUFL(buf,28)=gc->guild_id;
+ WBUFL(buf,24)=g->emblem_id;
+ }
+ }
+ } // End addition
+
+ WBUFPOS2(buf,50,md->bl.x,md->bl.y,md->to_x,md->to_y);
+ WBUFB(buf,56)=5;
+ WBUFB(buf,57)=5;
+ WBUFW(buf,58)=((level = battle_get_lv(&md->bl))>battle_config.max_lv)? battle_config.max_lv:level;
+
+ return packet_db[0x7b].len;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static int clif_npc0078(struct npc_data *nd, unsigned char *buf) {
+ struct guild *g;
+
+ nullpo_retr(0, nd);
+
+ memset(buf,0,packet_db[0x78].len);
+
+ WBUFW(buf,0)=0x78;
+ WBUFL(buf,2)=nd->bl.id;
+ WBUFW(buf,6)=nd->speed;
+ WBUFW(buf,14)=nd->class;
+ if ((nd->class == 722) && (nd->u.scr.guild_id > 0) && ((g=guild_search(nd->u.scr.guild_id)) != NULL)) {
+ WBUFL(buf,22)=g->emblem_id;
+ WBUFL(buf,26)=g->guild_id;
+ }
+ WBUFPOS(buf,46,nd->bl.x,nd->bl.y);
+ WBUFB(buf,48)|=nd->dir&0x0f;
+ WBUFB(buf,49)=5;
+ WBUFB(buf,50)=5;
+
+ return packet_db[0x78].len;
+}
+
+// NPC Walking [Valaris]
+static int clif_npc007b(struct npc_data *nd, unsigned char *buf) {
+ struct guild *g;
+
+ nullpo_retr(0, nd);
+
+ memset(buf,0,packet_db[0x7b].len);
+
+ WBUFW(buf,0)=0x7b;
+ WBUFL(buf,2)=nd->bl.id;
+ WBUFW(buf,6)=nd->speed;
+ WBUFW(buf,14)=nd->class;
+ if ((nd->class == 722) && (nd->u.scr.guild_id > 0) && ((g=guild_search(nd->u.scr.guild_id)) != NULL)) {
+ WBUFL(buf,22)=g->emblem_id;
+ WBUFL(buf,26)=g->guild_id;
+ }
+
+ WBUFL(buf,22)=gettick();
+ WBUFPOS2(buf,50,nd->bl.x,nd->bl.y,nd->to_x,nd->to_y);
+ WBUFB(buf,56)=5;
+ WBUFB(buf,57)=5;
+
+ return packet_db[0x7b].len;
+}
+
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static int clif_pet0078(struct pet_data *pd, unsigned char *buf) {
+ int view,level;
+
+ nullpo_retr(0, pd);
+
+ memset(buf,0,packet_db[0x78].len);
+
+ WBUFW(buf,0)=0x78;
+ WBUFL(buf,2)=pd->bl.id;
+ WBUFW(buf,6)=pd->speed;
+ WBUFW(buf,14)=mob_get_viewclass(pd->class);
+ if((mob_get_viewclass(pd->class) < 24) || (mob_get_viewclass(pd->class) > 4000)) {
+ WBUFW(buf,12)=mob_db[pd->class].option;
+ WBUFW(buf,16)=mob_get_hair(pd->class);
+ WBUFW(buf,18)=mob_get_weapon(pd->class);
+ WBUFW(buf,20)=mob_get_head_buttom(pd->class);
+ WBUFW(buf,22)=mob_get_shield(pd->class);
+ WBUFW(buf,24)=mob_get_head_top(pd->class);
+ WBUFW(buf,26)=mob_get_head_mid(pd->class);
+ WBUFW(buf,28)=mob_get_hair_color(pd->class);
+ WBUFW(buf,30)=mob_get_clothes_color(pd->class); //Add for player pet dye - Valaris
+ WBUFB(buf,45)=mob_get_sex(pd->class);
+ } else {
+ WBUFW(buf,16)=0x14;
+ if((view = itemdb_viewid(pd->equip)) > 0)
+ WBUFW(buf,20)=view;
+ else
+ WBUFW(buf,20)=pd->equip;
+ }
+ WBUFPOS(buf,46,pd->bl.x,pd->bl.y);
+ WBUFB(buf,48)|=pd->dir&0x0f;
+ WBUFB(buf,49)=0;
+ WBUFB(buf,50)=0;
+ WBUFW(buf,52)=((level = battle_get_lv(&pd->bl))>battle_config.max_lv)? battle_config.max_lv:level;
+
+ return packet_db[0x78].len;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static int clif_pet007b(struct pet_data *pd, unsigned char *buf) {
+ int view,level;
+
+ nullpo_retr(0, pd);
+
+ memset(buf,0,packet_db[0x7b].len);
+
+ WBUFW(buf,0)=0x7b;
+ WBUFL(buf,2)=pd->bl.id;
+ WBUFW(buf,6)=pd->speed;
+ WBUFW(buf,14)=mob_get_viewclass(pd->class);
+ if((mob_get_viewclass(pd->class) < 24) || (mob_get_viewclass(pd->class) > 4000)) {
+ WBUFW(buf,12)=mob_db[pd->class].option;
+ WBUFW(buf,16)=mob_get_hair(pd->class);
+ WBUFW(buf,18)=mob_get_weapon(pd->class);
+ WBUFW(buf,20)=mob_get_head_buttom(pd->class);
+ WBUFL(buf,22)=gettick();
+ WBUFW(buf,26)=mob_get_shield(pd->class);
+ WBUFW(buf,28)=mob_get_head_top(pd->class);
+ WBUFW(buf,30)=mob_get_head_mid(pd->class);
+ WBUFW(buf,32)=mob_get_hair_color(pd->class);
+ WBUFW(buf,34)=mob_get_clothes_color(pd->class); //Add for player pet dye - Valaris
+ WBUFB(buf,49)=mob_get_sex(pd->class);
+ } else {
+ WBUFW(buf,16)=0x14;
+ if ((view = itemdb_viewid(pd->equip)) > 0)
+ WBUFW(buf,20)=view;
+ else
+ WBUFW(buf,20)=pd->equip;
+ WBUFL(buf,22)=gettick();
+ }
+ WBUFPOS2(buf,50,pd->bl.x,pd->bl.y,pd->to_x,pd->to_y);
+ WBUFB(buf,56)=0;
+ WBUFB(buf,57)=0;
+ WBUFW(buf,58)=((level = battle_get_lv(&pd->bl))>battle_config.max_lv)? battle_config.max_lv:level;
+
+ return packet_db[0x7b].len;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static int clif_set01e1(struct map_session_data *sd, unsigned char *buf) {
+ nullpo_retr(0, sd);
+
+ WBUFW(buf,0)=0x1e1;
+ WBUFL(buf,2)=sd->bl.id;
+ WBUFW(buf,6)=sd->spiritball;
+
+ return packet_db[0x1e1].len;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static int clif_set0192(int fd, int m, int x, int y, int type) {
+ WFIFOW(fd,0) = 0x192;
+ WFIFOW(fd,2) = x;
+ WFIFOW(fd,4) = y;
+ WFIFOW(fd,6) = type;
+ memcpy(WFIFOP(fd,8),map[m].name,16);
+ WFIFOSET(fd,packet_db[0x192].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_spawnpc(struct map_session_data *sd) {
+ unsigned char buf[128];
+
+ nullpo_retr(0, sd);
+
+ if (sd->disguise > 23 && sd->disguise < 4001) { // mob disguises [Valaris]
+ clif_clearchar(&sd->bl, 9);
+
+ memset(buf, 0, packet_db[0x119].len);
+
+ WBUFW(buf, 0) = 0x119;
+ WBUFL(buf, 2) = sd->bl.id;
+ WBUFW(buf, 6) = 0;
+ WBUFW(buf, 8) = 0;
+ WBUFW(buf,10) = 0x40;
+ WBUFB(buf,12) = 0;
+
+ clif_send(buf, packet_db[0x119].len, &sd->bl, SELF);
+
+ memset(buf, 0, packet_db[0x7c].len);
+
+ WBUFW(buf, 0) = 0x7c;
+ WBUFL(buf, 2) = sd->bl.id;
+ WBUFW(buf, 6) = sd->speed;
+ WBUFW(buf, 8) = sd->opt1;
+ WBUFW(buf,10) = sd->opt2;
+ WBUFW(buf,12) = sd->status.option;
+ WBUFW(buf,20) = sd->disguise;
+ WBUFPOS(buf, 36, sd->bl.x, sd->bl.y);
+ clif_send(buf, packet_db[0x7c].len, &sd->bl, AREA);
+ }
+
+ clif_set0078(sd, buf);
+
+#if PACKETVER < 4
+ WBUFW(buf, 0) = 0x79;
+ WBUFW(buf,51) = (sd->status.base_level > battle_config.max_lv) ? battle_config.max_lv : sd->status.base_level;
+ clif_send(buf, packet_db[0x79].len, &sd->bl, AREA_WOS);
+#else
+ WBUFW(buf, 0) = 0x1d9;
+ WBUFW(buf,51) = (sd->status.base_level > battle_config.max_lv) ? battle_config.max_lv : sd->status.base_level;
+ clif_send(buf, packet_db[0x1d9].len, &sd->bl, AREA_WOS);
+#endif
+
+
+ if (sd->spiritball > 0)
+ clif_spiritball(sd);
+
+ if (sd->status.guild_id > 0) { // force display of guild emblem [Valaris]
+ struct guild *g = guild_search(sd->status.guild_id);
+ if (g)
+ clif_guild_emblem(sd,g);
+ } // end addition [Valaris]
+
+ if (sd->status.class==13 || sd->status.class==21 || sd->status.class==4014 || sd->status.class==4022)
+ pc_setoption(sd,sd->status.option|0x0020); // [Valaris]
+
+ if ((pc_isriding(sd) && pc_checkskill(sd,KN_RIDING)>0) && (sd->status.class==7 ||
+ sd->status.class==14 || sd->status.class==4008 || sd->status.class==4015))
+ pc_setriding(sd); // update peco riders for people upgrading athena [Valaris]
+
+
+ if (map[sd->bl.m].flag.snow)
+ clif_specialeffect(&sd->bl, 162, 1);
+ if (map[sd->bl.m].flag.fog)
+ clif_specialeffect(&sd->bl, 233, 1);
+ if (map[sd->bl.m].flag.sakura)
+ clif_specialeffect(&sd->bl, 163, 1);
+ if (map[sd->bl.m].flag.leaves)
+ clif_specialeffect(&sd->bl, 333, 1);
+ if (map[sd->bl.m].flag.rain)
+ clif_specialeffect(&sd->bl, 161, 1);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_spawnnpc(struct npc_data *nd)
+{
+ unsigned char buf[64];
+ int len;
+
+ nullpo_retr(0, nd);
+
+ if(nd->class < 0 || nd->flag&1 || nd->class == INVISIBLE_CLASS)
+ return 0;
+
+ memset(buf,0,packet_db[0x7c].len);
+
+ WBUFW(buf,0)=0x7c;
+ WBUFL(buf,2)=nd->bl.id;
+ WBUFW(buf,6)=nd->speed;
+ WBUFW(buf,20)=nd->class;
+ WBUFPOS(buf,36,nd->bl.x,nd->bl.y);
+
+ clif_send(buf,packet_db[0x7c].len,&nd->bl,AREA);
+
+ len = clif_npc0078(nd,buf);
+ clif_send(buf,len,&nd->bl,AREA);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_spawnmob(struct mob_data *md)
+{
+ unsigned char buf[64];
+ int len;
+
+ nullpo_retr(0, md);
+
+ if (mob_get_viewclass(md->class) > 23 ) {
+ memset(buf,0,packet_db[0x7c].len);
+
+ WBUFW(buf,0)=0x7c;
+ WBUFL(buf,2)=md->bl.id;
+ WBUFW(buf,6)=md->speed;
+ WBUFW(buf,8)=md->opt1;
+ WBUFW(buf,10)=md->opt2;
+ WBUFW(buf,12)=md->option;
+ WBUFW(buf,20)=mob_get_viewclass(md->class);
+ WBUFPOS(buf,36,md->bl.x,md->bl.y);
+ clif_send(buf,packet_db[0x7c].len,&md->bl,AREA);
+ }
+
+ len = clif_mob0078(md,buf);
+ clif_send(buf,len,&md->bl,AREA);
+
+ if (mob_get_equip(md->class) > 0) // mob equipment [Valaris]
+ clif_mob_equip(md,mob_get_equip(md->class));
+
+ return 0;
+}
+
+// pet
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_spawnpet(struct pet_data *pd)
+{
+ unsigned char buf[64];
+ int len;
+
+ nullpo_retr(0, pd);
+
+ if (mob_get_viewclass(pd->class) >= MAX_PC_CLASS) {
+ memset(buf,0,packet_db[0x7c].len);
+
+ WBUFW(buf,0)=0x7c;
+ WBUFL(buf,2)=pd->bl.id;
+ WBUFW(buf,6)=pd->speed;
+ WBUFW(buf,20)=mob_get_viewclass(pd->class);
+ WBUFPOS(buf,36,pd->bl.x,pd->bl.y);
+
+ clif_send(buf,packet_db[0x7c].len,&pd->bl,AREA);
+ }
+
+ len = clif_pet0078(pd,buf);
+ clif_send(buf,len,&pd->bl,AREA);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_movepet(struct pet_data *pd) {
+ unsigned char buf[256];
+ int len;
+
+ nullpo_retr(0, pd);
+
+ len = clif_pet007b(pd,buf);
+ clif_send(buf,len,&pd->bl,AREA);
+
+ return 0;
+}
+
+/*==========================================
+ * npc walking [Valaris]
+ *------------------------------------------
+ */
+int clif_movenpc(struct npc_data *nd) {
+ unsigned char buf[256];
+ int len;
+
+ nullpo_retr(0, nd);
+
+ len = clif_npc007b(nd,buf);
+ clif_send(buf,len,&nd->bl,AREA);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_servertick(struct map_session_data *sd)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x7f;
+ WFIFOL(fd,2)=sd->server_tick;
+ WFIFOSET(fd,packet_db[0x7f].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_walkok(struct map_session_data *sd)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x87;
+ WFIFOL(fd,2)=gettick();;
+ WFIFOPOS2(fd,6,sd->bl.x,sd->bl.y,sd->to_x,sd->to_y);
+ WFIFOB(fd,11)=0;
+ WFIFOSET(fd,packet_db[0x87].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_movechar(struct map_session_data *sd) {
+ int fd;
+ int len;
+ unsigned char buf[256];
+
+ nullpo_retr(0, sd);
+
+ fd = sd->fd;
+
+ len = clif_set007b(sd, buf);
+
+ if (sd->disguise > 23 && sd->disguise < 4001) {
+ clif_send(buf, len, &sd->bl, AREA);
+ return 0;
+ } else
+ clif_send(buf, len, &sd->bl, AREA_WOS);
+
+ if (battle_config.save_clothcolor == 1 && sd->status.clothes_color > 0)
+ clif_changelook(&sd->bl, LOOK_CLOTHES_COLOR, sd->status.clothes_color);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_quitsave(int fd,struct map_session_data *sd)
+{
+ map_quit(sd);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static int clif_waitclose(int tid, unsigned int tick, int id, int data) {
+ if (session[id])
+ session[id]->eof = 1;
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_setwaitclose(int fd) {
+ add_timer(gettick() + 5000, clif_waitclose, fd, 0);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_changemap(struct map_session_data *sd, char *mapname, int x, int y) {
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd = sd->fd;
+
+ WFIFOW(fd,0) = 0x91;
+ memcpy(WFIFOP(fd,2), mapname, 16);
+ WFIFOW(fd,18) = x;
+ WFIFOW(fd,20) = y;
+ WFIFOSET(fd, packet_db[0x91].len);
+
+ if (sd->disguise > 23 && sd->disguise < 4001) // mob disguises [Valaris]
+ clif_spawnpc(sd);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_changemapserver(struct map_session_data *sd, char *mapname, int x, int y, int ip, int port) {
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd = sd->fd;
+ WFIFOW(fd,0) = 0x92;
+ memcpy(WFIFOP(fd,2), mapname, 16);
+ WFIFOW(fd,18) = x;
+ WFIFOW(fd,20) = y;
+ WFIFOL(fd,22) = ip;
+ WFIFOW(fd,26) = port;
+ WFIFOSET(fd, packet_db[0x92].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_fixpos(struct block_list *bl) {
+ char buf[16];
+
+ nullpo_retr(0, bl);
+
+ WBUFW(buf,0)=0x88;
+ WBUFL(buf,2)=bl->id;
+ WBUFW(buf,6)=bl->x;
+ WBUFW(buf,8)=bl->y;
+
+ clif_send(buf, packet_db[0x88].len, bl, AREA);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_npcbuysell(struct map_session_data* sd, int id) {
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xc4;
+ WFIFOL(fd,2)=id;
+ WFIFOSET(fd,packet_db[0xc4].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_buylist(struct map_session_data *sd, struct npc_data *nd) {
+ struct item_data *id;
+ int fd,i,val;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, nd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xc6;
+ for(i=0;nd->u.shop_item[i].nameid > 0;i++){
+ id = itemdb_search(nd->u.shop_item[i].nameid);
+ val=nd->u.shop_item[i].value;
+ WFIFOL(fd,4+i*11)=val;
+ if (!id->flag.value_notdc)
+ val=pc_modifybuyvalue(sd,val);
+ WFIFOL(fd,8+i*11)=val;
+ WFIFOB(fd,12+i*11)=id->type;
+ if (id->view_id > 0)
+ WFIFOW(fd,13+i*11)=id->view_id;
+ else
+ WFIFOW(fd,13+i*11)=nd->u.shop_item[i].nameid;
+ }
+ WFIFOW(fd,2)=i*11+4;
+ WFIFOSET(fd,WFIFOW(fd,2));
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_selllist(struct map_session_data *sd) {
+ int fd,i,c=0,val;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xc7;
+ for(i=0;i<MAX_INVENTORY;i++) {
+ if(sd->status.inventory[i].nameid > 0 && sd->inventory_data[i]) {
+ val=sd->inventory_data[i]->value_sell;
+ if (val < 0)
+ continue;
+ WFIFOW(fd,4+c*10)=i+2;
+ WFIFOL(fd,6+c*10)=val;
+ if (!sd->inventory_data[i]->flag.value_notoc)
+ val=pc_modifysellvalue(sd,val);
+ WFIFOL(fd,10+c*10)=val;
+ c++;
+ }
+ }
+ WFIFOW(fd,2)=c*10+4;
+ WFIFOSET(fd,WFIFOW(fd,2));
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_scriptmes(struct map_session_data *sd, int npcid, char *mes) {
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xb4;
+ WFIFOW(fd,2)=strlen(mes)+9;
+ WFIFOL(fd,4)=npcid;
+ strcpy(WFIFOP(fd,8),mes);
+ WFIFOSET(fd,WFIFOW(fd,2));
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_scriptnext(struct map_session_data *sd,int npcid) {
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xb5;
+ WFIFOL(fd,2)=npcid;
+ WFIFOSET(fd,packet_db[0xb5].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_scriptclose(struct map_session_data *sd, int npcid) {
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xb6;
+ WFIFOL(fd,2)=npcid;
+ WFIFOSET(fd,packet_db[0xb6].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_scriptmenu(struct map_session_data *sd, int npcid, char *mes) {
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xb7;
+ WFIFOW(fd,2)=strlen(mes)+8;
+ WFIFOL(fd,4)=npcid;
+ strcpy(WFIFOP(fd,8),mes);
+ WFIFOSET(fd,WFIFOW(fd,2));
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_scriptinput(struct map_session_data *sd, int npcid) {
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x142;
+ WFIFOL(fd,2)=npcid;
+ WFIFOSET(fd,packet_db[0x142].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_scriptinputstr(struct map_session_data *sd, int npcid) {
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x1d4;
+ WFIFOL(fd,2)=npcid;
+ WFIFOSET(fd,packet_db[0x1d4].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_viewpoint(struct map_session_data *sd, int npc_id, int type, int x, int y, int id, int color) {
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x144;
+ WFIFOL(fd,2)=npc_id;
+ WFIFOL(fd,6)=type;
+ WFIFOL(fd,10)=x;
+ WFIFOL(fd,14)=y;
+ WFIFOB(fd,18)=id;
+ WFIFOL(fd,19)=color;
+ WFIFOSET(fd,packet_db[0x144].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_cutin(struct map_session_data *sd, char *image, int type) {
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x1b3;
+ memcpy(WFIFOP(fd,2),image,64);
+ WFIFOB(fd,66)=type;
+ WFIFOSET(fd,packet_db[0x1b3].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_additem(struct map_session_data *sd, int n, int amount, int fail) {
+ int fd,j;
+ unsigned char *buf;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ buf=WFIFOP(fd,0);
+ if(fail) {
+ WBUFW(buf,0)=0xa0;
+ WBUFW(buf,2)=n+2;
+ WBUFW(buf,4)=amount;
+ WBUFW(buf,6)=0;
+ WBUFB(buf,8)=0;
+ WBUFB(buf,9)=0;
+ WBUFB(buf,10)=0;
+ WBUFW(buf,11)=0;
+ WBUFW(buf,13)=0;
+ WBUFW(buf,15)=0;
+ WBUFW(buf,17)=0;
+ WBUFW(buf,19)=0;
+ WBUFB(buf,21)=0;
+ WBUFB(buf,22)=fail;
+ } else {
+ if (n<0 || n>=MAX_INVENTORY || sd->status.inventory[n].nameid <=0 || sd->inventory_data[n] == NULL)
+ return 1;
+
+ WBUFW(buf,0)=0xa0;
+ WBUFW(buf,2)=n+2;
+ WBUFW(buf,4)=amount;
+ if (sd->inventory_data[n]->view_id > 0)
+ WBUFW(buf,6)=sd->inventory_data[n]->view_id;
+ else
+ WBUFW(buf,6)=sd->status.inventory[n].nameid;
+ WBUFB(buf,8)=sd->status.inventory[n].identify;
+ WBUFB(buf,9)=sd->status.inventory[n].attribute;
+ WBUFB(buf,10)=sd->status.inventory[n].refine;
+ if(sd->status.inventory[n].card[0]==0x00ff || sd->status.inventory[n].card[0]==0x00fe || sd->status.inventory[n].card[0]==(short)0xff00) {
+ WBUFW(buf,11)=sd->status.inventory[n].card[0];
+ WBUFW(buf,13)=sd->status.inventory[n].card[1];
+ WBUFW(buf,15)=sd->status.inventory[n].card[2];
+ WBUFW(buf,17)=sd->status.inventory[n].card[3];
+ } else {
+ if (sd->status.inventory[n].card[0] > 0 && (j=itemdb_viewid(sd->status.inventory[n].card[0])) > 0)
+ WBUFW(buf,11)=j;
+ else
+ WBUFW(buf,11)=sd->status.inventory[n].card[0];
+ if (sd->status.inventory[n].card[1] > 0 && (j=itemdb_viewid(sd->status.inventory[n].card[1])) > 0)
+ WBUFW(buf,13)=j;
+ else
+ WBUFW(buf,13)=sd->status.inventory[n].card[1];
+ if (sd->status.inventory[n].card[2] > 0 && (j=itemdb_viewid(sd->status.inventory[n].card[2])) > 0)
+ WBUFW(buf,15)=j;
+ else
+ WBUFW(buf,15)=sd->status.inventory[n].card[2];
+ if (sd->status.inventory[n].card[3] > 0 && (j=itemdb_viewid(sd->status.inventory[n].card[3])) > 0)
+ WBUFW(buf,17)=j;
+ else
+ WBUFW(buf,17)=sd->status.inventory[n].card[3];
+ }
+ WBUFW(buf,19)=pc_equippoint(sd,n);
+ WBUFB(buf,21)=(sd->inventory_data[n]->type == 7)? 4:sd->inventory_data[n]->type;
+ WBUFB(buf,22)=fail;
+ }
+
+ WFIFOSET(fd,packet_db[0xa0].len);
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_delitem(struct map_session_data *sd,int n,int amount)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xaf;
+ WFIFOW(fd,2)=n+2;
+ WFIFOW(fd,4)=amount;
+
+ WFIFOSET(fd,packet_db[0xaf].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_itemlist(struct map_session_data *sd)
+{
+ int i,n,fd,arrow=-1;
+ unsigned char *buf;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ buf = WFIFOP(fd,0);
+#if PACKETVER < 5
+ WBUFW(buf,0)=0xa3;
+ for(i=0,n=0;i<MAX_INVENTORY;i++){
+ if (sd->status.inventory[i].nameid <=0 || sd->inventory_data[i] == NULL || itemdb_isequip2(sd->inventory_data[i]))
+ continue;
+ WBUFW(buf,n*10+4)=i+2;
+ if (sd->inventory_data[i]->view_id > 0)
+ WBUFW(buf,n*10+6)=sd->inventory_data[i]->view_id;
+ else
+ WBUFW(buf,n*10+6)=sd->status.inventory[i].nameid;
+ WBUFB(buf,n*10+8)=sd->inventory_data[i]->type;
+ WBUFB(buf,n*10+9)=sd->status.inventory[i].identify;
+ WBUFW(buf,n*10+10)=sd->status.inventory[i].amount;
+ if (sd->inventory_data[i]->equip == 0x8000) {
+ WBUFW(buf,n*10+12)=0x8000;
+ if (sd->status.inventory[i].equip)
+ arrow=i; // ついでに矢装備チェック
+ } else
+ WBUFW(buf,n*10+12)=0;
+ n++;
+ }
+ if (n) {
+ WBUFW(buf,2)=4+n*10;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+#else
+ WBUFW(buf,0)=0x1ee;
+ for(i=0,n=0;i<MAX_INVENTORY;i++){
+ if(sd->status.inventory[i].nameid <=0 || sd->inventory_data[i] == NULL || itemdb_isequip2(sd->inventory_data[i]))
+ continue;
+ WBUFW(buf,n*18+4)=i+2;
+ if(sd->inventory_data[i]->view_id > 0)
+ WBUFW(buf,n*18+6)=sd->inventory_data[i]->view_id;
+ else
+ WBUFW(buf,n*18+6)=sd->status.inventory[i].nameid;
+ WBUFB(buf,n*18+8)=sd->inventory_data[i]->type;
+ WBUFB(buf,n*18+9)=sd->status.inventory[i].identify;
+ WBUFW(buf,n*18+10)=sd->status.inventory[i].amount;
+ if (sd->inventory_data[i]->equip == 0x8000) {
+ WBUFW(buf,n*18+12)=0x8000;
+ if(sd->status.inventory[i].equip)
+ arrow=i; // ついでに矢装備チェック
+ } else
+ WBUFW(buf,n*18+12)=0;
+ WBUFW(buf,n*18+14)=sd->status.inventory[i].card[0];
+ WBUFW(buf,n*18+16)=sd->status.inventory[i].card[1];
+ WBUFW(buf,n*18+18)=sd->status.inventory[i].card[2];
+ WBUFW(buf,n*18+20)=sd->status.inventory[i].card[3];
+ n++;
+ }
+ if (n) {
+ WBUFW(buf,2)=4+n*18;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+#endif
+ if(arrow >= 0)
+ clif_arrowequip(sd,arrow);
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_equiplist(struct map_session_data *sd)
+{
+ int i,j,n,fd;
+ unsigned char *buf;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ buf = WFIFOP(fd,0);
+ WBUFW(buf,0)=0xa4;
+ for(i=0,n=0;i<MAX_INVENTORY;i++){
+ if(sd->status.inventory[i].nameid<=0 || sd->inventory_data[i] == NULL || !itemdb_isequip2(sd->inventory_data[i]))
+ continue;
+ WBUFW(buf,n*20+4)=i+2;
+ if(sd->inventory_data[i]->view_id > 0)
+ WBUFW(buf,n*20+6)=sd->inventory_data[i]->view_id;
+ else
+ WBUFW(buf,n*20+6)=sd->status.inventory[i].nameid;
+ WBUFB(buf,n*20+8)=(sd->inventory_data[i]->type == 7)? 4:sd->inventory_data[i]->type;
+ WBUFB(buf,n*20+9)=sd->status.inventory[i].identify;
+ WBUFW(buf,n*20+10)=pc_equippoint(sd,i);
+ WBUFW(buf,n*20+12)=sd->status.inventory[i].equip;
+ WBUFB(buf,n*20+14)=sd->status.inventory[i].attribute;
+ WBUFB(buf,n*20+15)=sd->status.inventory[i].refine;
+ if(sd->status.inventory[i].card[0]==0x00ff || sd->status.inventory[i].card[0]==0x00fe || sd->status.inventory[i].card[0]==(short)0xff00) {
+ WBUFW(buf,n*20+16)=sd->status.inventory[i].card[0];
+ WBUFW(buf,n*20+18)=sd->status.inventory[i].card[1];
+ WBUFW(buf,n*20+20)=sd->status.inventory[i].card[2];
+ WBUFW(buf,n*20+22)=sd->status.inventory[i].card[3];
+ } else {
+ if(sd->status.inventory[i].card[0] > 0 && (j=itemdb_viewid(sd->status.inventory[i].card[0])) > 0)
+ WBUFW(buf,n*20+16)=j;
+ else
+ WBUFW(buf,n*20+16)=sd->status.inventory[i].card[0];
+ if(sd->status.inventory[i].card[1] > 0 && (j=itemdb_viewid(sd->status.inventory[i].card[1])) > 0)
+ WBUFW(buf,n*20+18)=j;
+ else
+ WBUFW(buf,n*20+18)=sd->status.inventory[i].card[1];
+ if(sd->status.inventory[i].card[2] > 0 && (j=itemdb_viewid(sd->status.inventory[i].card[2])) > 0)
+ WBUFW(buf,n*20+20)=j;
+ else
+ WBUFW(buf,n*20+20)=sd->status.inventory[i].card[2];
+ if(sd->status.inventory[i].card[3] > 0 && (j=itemdb_viewid(sd->status.inventory[i].card[3])) > 0)
+ WBUFW(buf,n*20+22)=j;
+ else
+ WBUFW(buf,n*20+22)=sd->status.inventory[i].card[3];
+ }
+ n++;
+ }
+ if(n){
+ WBUFW(buf,2)=4+n*20;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+ return 0;
+}
+
+/*==========================================
+ * カプラさんに預けてある消耗品&収集品リスト
+ *------------------------------------------
+ */
+int clif_storageitemlist(struct map_session_data *sd,struct storage *stor)
+{
+ struct item_data *id;
+ int i,n,fd;
+ unsigned char *buf;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor);
+
+ fd=sd->fd;
+ buf = WFIFOP(fd,0);
+#if PACKETVER < 5
+ WBUFW(buf,0)=0xa5;
+ for(i=0,n=0;i<MAX_STORAGE;i++){
+ if(stor->storage[i].nameid<=0)
+ continue;
+ nullpo_retr(0, id = itemdb_search(stor->storage[i].nameid));
+ if(itemdb_isequip2(id))
+ continue;
+
+ WBUFW(buf,n*10+4)=i+1;
+ if(id->view_id > 0)
+ WBUFW(buf,n*10+6)=id->view_id;
+ else
+ WBUFW(buf,n*10+6)=stor->storage[i].nameid;
+ WBUFB(buf,n*10+8)=id->type;;
+ WBUFB(buf,n*10+9)=stor->storage[i].identify;
+ WBUFW(buf,n*10+10)=stor->storage[i].amount;
+ WBUFW(buf,n*10+12)=0;
+ n++;
+ }
+ if(n){
+ WBUFW(buf,2)=4+n*10;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+#else
+ WBUFW(buf,0)=0x1f0;
+ for(i=0,n=0;i<MAX_STORAGE;i++){
+ if(stor->storage[i].nameid<=0)
+ continue;
+ nullpo_retr(0, id = itemdb_search(stor->storage[i].nameid));
+ if(itemdb_isequip2(id))
+ continue;
+
+ WBUFW(buf,n*18+4)=i+1;
+ if(id->view_id > 0)
+ WBUFW(buf,n*18+6)=id->view_id;
+ else
+ WBUFW(buf,n*18+6)=stor->storage[i].nameid;
+ WBUFB(buf,n*18+8)=id->type;;
+ WBUFB(buf,n*18+9)=stor->storage[i].identify;
+ WBUFW(buf,n*18+10)=stor->storage[i].amount;
+ WBUFW(buf,n*18+12)=0;
+ WBUFW(buf,n*18+14)=stor->storage[i].card[0];
+ WBUFW(buf,n*18+16)=stor->storage[i].card[1];
+ WBUFW(buf,n*18+18)=stor->storage[i].card[2];
+ WBUFW(buf,n*18+20)=stor->storage[i].card[3];
+ n++;
+ }
+ if(n){
+ WBUFW(buf,2)=4+n*18;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+#endif
+ return 0;
+}
+
+/*==========================================
+ * カプラさんに預けてある装備リスト
+ *------------------------------------------
+ */
+int clif_storageequiplist(struct map_session_data *sd,struct storage *stor)
+{
+ struct item_data *id;
+ int i,j,n,fd;
+ unsigned char *buf;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor);
+
+ fd=sd->fd;
+ buf = WFIFOP(fd,0);
+ WBUFW(buf,0)=0xa6;
+ for(i=0,n=0;i<MAX_STORAGE;i++){
+ if(stor->storage[i].nameid<=0)
+ continue;
+ nullpo_retr(0, id = itemdb_search(stor->storage[i].nameid));
+ if(!itemdb_isequip2(id))
+ continue;
+ WBUFW(buf,n*20+4)=i+1;
+ if(id->view_id > 0)
+ WBUFW(buf,n*20+6)=id->view_id;
+ else
+ WBUFW(buf,n*20+6)=stor->storage[i].nameid;
+ WBUFB(buf,n*20+8)=id->type;
+ WBUFB(buf,n*20+9)=stor->storage[i].identify;
+ WBUFW(buf,n*20+10)=id->equip;
+ WBUFW(buf,n*20+12)=stor->storage[i].equip;
+ WBUFB(buf,n*20+14)=stor->storage[i].attribute;
+ WBUFB(buf,n*20+15)=stor->storage[i].refine;
+ if(stor->storage[i].card[0]==0x00ff || stor->storage[i].card[0]==0x00fe || stor->storage[i].card[0]==(short)0xff00) {
+ WBUFW(buf,n*20+16)=stor->storage[i].card[0];
+ WBUFW(buf,n*20+18)=stor->storage[i].card[1];
+ WBUFW(buf,n*20+20)=stor->storage[i].card[2];
+ WBUFW(buf,n*20+22)=stor->storage[i].card[3];
+ } else {
+ if(stor->storage[i].card[0] > 0 && (j=itemdb_viewid(stor->storage[i].card[0])) > 0)
+ WBUFW(buf,n*20+16)=j;
+ else
+ WBUFW(buf,n*20+16)=stor->storage[i].card[0];
+ if(stor->storage[i].card[1] > 0 && (j=itemdb_viewid(stor->storage[i].card[1])) > 0)
+ WBUFW(buf,n*20+18)=j;
+ else
+ WBUFW(buf,n*20+18)=stor->storage[i].card[1];
+ if(stor->storage[i].card[2] > 0 && (j=itemdb_viewid(stor->storage[i].card[2])) > 0)
+ WBUFW(buf,n*20+20)=j;
+ else
+ WBUFW(buf,n*20+20)=stor->storage[i].card[2];
+ if(stor->storage[i].card[3] > 0 && (j=itemdb_viewid(stor->storage[i].card[3])) > 0)
+ WBUFW(buf,n*20+22)=j;
+ else
+ WBUFW(buf,n*20+22)=stor->storage[i].card[3];
+ }
+ n++;
+ }
+ if(n){
+ WBUFW(buf,2)=4+n*20;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_guildstorageitemlist(struct map_session_data *sd,struct guild_storage *stor)
+{
+ struct item_data *id;
+ int i,n,fd;
+ unsigned char *buf;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor);
+
+ fd=sd->fd;
+ buf=WFIFOP(fd,0);
+
+#if PACKETVER < 5
+ WBUFW(buf,0)=0xa5;
+ for(i=0,n=0;i<MAX_GUILD_STORAGE;i++){
+ if(stor->storage[i].nameid<=0)
+ continue;
+ nullpo_retr(0, id = itemdb_search(stor->storage[i].nameid));
+ if(itemdb_isequip2(id))
+ continue;
+
+ WBUFW(buf,n*10+4)=i+1;
+ if(id->view_id > 0)
+ WBUFW(buf,n*10+6)=id->view_id;
+ else
+ WBUFW(buf,n*10+6)=stor->storage[i].nameid;
+ WBUFB(buf,n*10+8)=id->type;;
+ WBUFB(buf,n*10+9)=stor->storage[i].identify;
+ WBUFW(buf,n*10+10)=stor->storage[i].amount;
+ WBUFW(buf,n*10+12)=0;
+ n++;
+ }
+ if(n){
+ WBUFW(buf,2)=4+n*10;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+#else
+ WBUFW(buf,0)=0x1f0;
+ for(i=0,n=0;i<MAX_GUILD_STORAGE;i++){
+ if(stor->storage[i].nameid<=0)
+ continue;
+ nullpo_retr(0, id = itemdb_search(stor->storage[i].nameid));
+ if(itemdb_isequip2(id))
+ continue;
+
+ WBUFW(buf,n*18+4)=i+1;
+ if(id->view_id > 0)
+ WBUFW(buf,n*18+6)=id->view_id;
+ else
+ WBUFW(buf,n*18+6)=stor->storage[i].nameid;
+ WBUFB(buf,n*18+8)=id->type;;
+ WBUFB(buf,n*18+9)=stor->storage[i].identify;
+ WBUFW(buf,n*18+10)=stor->storage[i].amount;
+ WBUFW(buf,n*18+12)=0;
+ WBUFW(buf,n*18+14)=stor->storage[i].card[0];
+ WBUFW(buf,n*18+16)=stor->storage[i].card[1];
+ WBUFW(buf,n*18+18)=stor->storage[i].card[2];
+ WBUFW(buf,n*18+20)=stor->storage[i].card[3];
+ n++;
+ }
+ if(n){
+ WBUFW(buf,2)=4+n*18;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+#endif
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_guildstorageequiplist(struct map_session_data *sd,struct guild_storage *stor)
+{
+ struct item_data *id;
+ int i,j,n,fd;
+ unsigned char *buf;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ buf=WFIFOP(fd,0);
+
+ WBUFW(buf,0)=0xa6;
+ for(i=0,n=0;i<MAX_GUILD_STORAGE;i++){
+ if(stor->storage[i].nameid<=0)
+ continue;
+ nullpo_retr(0, id = itemdb_search(stor->storage[i].nameid));
+ if(!itemdb_isequip2(id))
+ continue;
+ WBUFW(buf,n*20+4)=i+1;
+ if(id->view_id > 0)
+ WBUFW(buf,n*20+6)=id->view_id;
+ else
+ WBUFW(buf,n*20+6)=stor->storage[i].nameid;
+ WBUFB(buf,n*20+8)=id->type;
+ WBUFB(buf,n*20+9)=stor->storage[i].identify;
+ WBUFW(buf,n*20+10)=id->equip;
+ WBUFW(buf,n*20+12)=stor->storage[i].equip;
+ WBUFB(buf,n*20+14)=stor->storage[i].attribute;
+ WBUFB(buf,n*20+15)=stor->storage[i].refine;
+ if(stor->storage[i].card[0]==0x00ff || stor->storage[i].card[0]==0x00fe || stor->storage[i].card[0]==(short)0xff00) {
+ WBUFW(buf,n*20+16)=stor->storage[i].card[0];
+ WBUFW(buf,n*20+18)=stor->storage[i].card[1];
+ WBUFW(buf,n*20+20)=stor->storage[i].card[2];
+ WBUFW(buf,n*20+22)=stor->storage[i].card[3];
+ } else {
+ if(stor->storage[i].card[0] > 0 && (j=itemdb_viewid(stor->storage[i].card[0])) > 0)
+ WBUFW(buf,n*20+16)=j;
+ else
+ WBUFW(buf,n*20+16)=stor->storage[i].card[0];
+ if(stor->storage[i].card[1] > 0 && (j=itemdb_viewid(stor->storage[i].card[1])) > 0)
+ WBUFW(buf,n*20+18)=j;
+ else
+ WBUFW(buf,n*20+18)=stor->storage[i].card[1];
+ if(stor->storage[i].card[2] > 0 && (j=itemdb_viewid(stor->storage[i].card[2])) > 0)
+ WBUFW(buf,n*20+20)=j;
+ else
+ WBUFW(buf,n*20+20)=stor->storage[i].card[2];
+ if(stor->storage[i].card[3] > 0 && (j=itemdb_viewid(stor->storage[i].card[3])) > 0)
+ WBUFW(buf,n*20+22)=j;
+ else
+ WBUFW(buf,n*20+22)=stor->storage[i].card[3];
+ }
+ n++;
+ }
+ if(n){
+ WBUFW(buf,2)=4+n*20;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+ return 0;
+}
+
+/*==========================================
+ * ステータスを送りつける
+ * 表示専用数字はこの中で計算して送る
+ *------------------------------------------
+ */
+int clif_updatestatus(struct map_session_data *sd,int type)
+{
+ int fd,len=8;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+
+ WFIFOW(fd,0)=0xb0;
+ WFIFOW(fd,2)=type;
+ switch(type){
+ // 00b0
+ case SP_WEIGHT:
+ pc_checkweighticon(sd);
+ WFIFOW(fd,0)=0xb0;
+ WFIFOW(fd,2)=type;
+ WFIFOL(fd,4)=sd->weight;
+ break;
+ case SP_MAXWEIGHT:
+ WFIFOL(fd,4)=sd->max_weight;
+ break;
+ case SP_SPEED:
+ WFIFOL(fd,4)=sd->speed;
+ break;
+ case SP_BASELEVEL:
+ WFIFOL(fd,4)=sd->status.base_level;
+ break;
+ case SP_JOBLEVEL:
+ WFIFOL(fd,4)=sd->status.job_level;
+ break;
+ case SP_MANNER:
+ WFIFOL(fd,4)=sd->status.manner;
+ clif_changestatus(&sd->bl,SP_MANNER,sd->status.manner);
+ break;
+ case SP_STATUSPOINT:
+ WFIFOL(fd,4)=sd->status.status_point;
+ break;
+ case SP_SKILLPOINT:
+ WFIFOL(fd,4)=sd->status.skill_point;
+ break;
+ case SP_HIT:
+ WFIFOL(fd,4)=sd->hit;
+ break;
+ case SP_FLEE1:
+ WFIFOL(fd,4)=sd->flee;
+ break;
+ case SP_FLEE2:
+ WFIFOL(fd,4)=sd->flee2/10;
+ break;
+ case SP_MAXHP:
+ WFIFOL(fd,4)=sd->status.max_hp;
+ break;
+ case SP_MAXSP:
+ WFIFOL(fd,4)=sd->status.max_sp;
+ break;
+ case SP_HP:
+ WFIFOL(fd,4)=sd->status.hp;
+ break;
+ case SP_SP:
+ WFIFOL(fd,4)=sd->status.sp;
+ break;
+ case SP_ASPD:
+ WFIFOL(fd,4)=sd->aspd;
+ break;
+ case SP_ATK1:
+ WFIFOL(fd,4)=sd->base_atk+sd->watk;
+ break;
+ case SP_DEF1:
+ WFIFOL(fd,4)=sd->def;
+ break;
+ case SP_MDEF1:
+ WFIFOL(fd,4)=sd->mdef;
+ break;
+ case SP_ATK2:
+ WFIFOL(fd,4)=sd->watk2;
+ break;
+ case SP_DEF2:
+ WFIFOL(fd,4)=sd->def2;
+ break;
+ case SP_MDEF2:
+ WFIFOL(fd,4)=sd->mdef2;
+ break;
+ case SP_CRITICAL:
+ WFIFOL(fd,4)=sd->critical/10;
+ break;
+ case SP_MATK1:
+ WFIFOL(fd,4)=sd->matk1;
+ break;
+ case SP_MATK2:
+ WFIFOL(fd,4)=sd->matk2;
+ break;
+
+
+ case SP_ZENY:
+ WFIFOW(fd,0)=0xb1;
+ if(sd->status.zeny < 0)
+ sd->status.zeny = 0;
+ WFIFOL(fd,4)=sd->status.zeny;
+ break;
+ case SP_BASEEXP:
+ WFIFOW(fd,0)=0xb1;
+ WFIFOL(fd,4)=sd->status.base_exp;
+ break;
+ case SP_JOBEXP:
+ WFIFOW(fd,0)=0xb1;
+ WFIFOL(fd,4)=sd->status.job_exp;
+ break;
+ case SP_NEXTBASEEXP:
+ WFIFOW(fd,0)=0xb1;
+ WFIFOL(fd,4)=pc_nextbaseexp(sd);
+ break;
+ case SP_NEXTJOBEXP:
+ WFIFOW(fd,0)=0xb1;
+ WFIFOL(fd,4)=pc_nextjobexp(sd);
+ break;
+
+ // 00be 終了
+ case SP_USTR:
+ case SP_UAGI:
+ case SP_UVIT:
+ case SP_UINT:
+ case SP_UDEX:
+ case SP_ULUK:
+ WFIFOW(fd,0)=0xbe;
+ WFIFOB(fd,4)=pc_need_status_point(sd,type-SP_USTR+SP_STR);
+ len=5;
+ break;
+
+ // 013a 終了
+ case SP_ATTACKRANGE:
+ WFIFOW(fd,0)=0x13a;
+ WFIFOW(fd,2)=sd->attackrange;
+ len=4;
+ break;
+
+ // 0141 終了
+ case SP_STR:
+ WFIFOW(fd,0)=0x141;
+ WFIFOL(fd,2)=type;
+ WFIFOL(fd,6)=sd->status.str;
+ WFIFOL(fd,10)=sd->paramb[0] + sd->parame[0];
+ len=14;
+ break;
+ case SP_AGI:
+ WFIFOW(fd,0)=0x141;
+ WFIFOL(fd,2)=type;
+ WFIFOL(fd,6)=sd->status.agi;
+ WFIFOL(fd,10)=sd->paramb[1] + sd->parame[1];
+ len=14;
+ break;
+ case SP_VIT:
+ WFIFOW(fd,0)=0x141;
+ WFIFOL(fd,2)=type;
+ WFIFOL(fd,6)=sd->status.vit;
+ WFIFOL(fd,10)=sd->paramb[2] + sd->parame[2];
+ len=14;
+ break;
+ case SP_INT:
+ WFIFOW(fd,0)=0x141;
+ WFIFOL(fd,2)=type;
+ WFIFOL(fd,6)=sd->status.int_;
+ WFIFOL(fd,10)=sd->paramb[3] + sd->parame[3];
+ len=14;
+ break;
+ case SP_DEX:
+ WFIFOW(fd,0)=0x141;
+ WFIFOL(fd,2)=type;
+ WFIFOL(fd,6)=sd->status.dex;
+ WFIFOL(fd,10)=sd->paramb[4] + sd->parame[4];
+ len=14;
+ break;
+ case SP_LUK:
+ WFIFOW(fd,0)=0x141;
+ WFIFOL(fd,2)=type;
+ WFIFOL(fd,6)=sd->status.luk;
+ WFIFOL(fd,10)=sd->paramb[5] + sd->parame[5];
+ len=14;
+ break;
+
+ case SP_CARTINFO:
+ WFIFOW(fd,0)=0x121;
+ WFIFOW(fd,2)=sd->cart_num;
+ WFIFOW(fd,4)=sd->cart_max_num;
+ WFIFOL(fd,6)=sd->cart_weight;
+ WFIFOL(fd,10)=sd->cart_max_weight;
+ len=14;
+ break;
+
+ default:
+ if(battle_config.error_log)
+ printf("clif_updatestatus : make %d routine\n",type);
+ return 1;
+ }
+ WFIFOSET(fd,len);
+
+ return 0;
+}
+int clif_changestatus(struct block_list *bl,int type,int val)
+{
+ unsigned char buf[12];
+ struct map_session_data *sd = NULL;
+
+ nullpo_retr(0, bl);
+
+ if(bl->type == BL_PC)
+ sd = (struct map_session_data *)bl;
+
+//printf("clif_changestatus id:%d type:%d val:%d\n",bl->id,type,val);
+ if(sd){
+ WBUFW(buf,0)=0x1ab;
+ WBUFL(buf,2)=bl->id;
+ WBUFW(buf,6)=type;
+ switch(type){
+ case SP_MANNER:
+ WBUFL(buf,8)=val;
+ break;
+ default:
+ if(battle_config.error_log)
+ printf("clif_changestatus : make %d routine\n",type);
+ return 1;
+ }
+ clif_send(buf,packet_db[0x1ab].len,bl,AREA_WOS);
+ }
+ return 0;
+}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_changelook(struct block_list *bl,int type,int val)
+{
+
+ unsigned char buf[32];
+ struct map_session_data *sd = NULL;
+
+ nullpo_retr(0, bl);
+
+ if(bl->type == BL_PC)
+ sd = (struct map_session_data *)bl;
+
+ if(sd && sd->disguise > 23 && sd->disguise < 4001) // mob disguises [Valaris]
+ return 0;
+
+#if PACKETVER < 4
+ if(sd && (type == LOOK_WEAPON || type == LOOK_SHIELD) && sd->view_class == 22)
+ val =0;
+ WBUFW(buf,0)=0xc3;
+ WBUFL(buf,2)=bl->id;
+ WBUFB(buf,6)=type;
+ WBUFB(buf,7)=val;
+ clif_send(buf,packet_db[0xc3].len,bl,AREA);
+#else
+ if(sd && (type == LOOK_WEAPON || type == LOOK_SHIELD || type == LOOK_SHOES)) {
+ WBUFW(buf,0)=0x1d7;
+ WBUFL(buf,2)=bl->id;
+ if(type == LOOK_SHOES) {
+ WBUFB(buf,6)=9;
+ if(sd->equip_index[2] >= 0 && sd->inventory_data[sd->equip_index[2]]) {
+ if(sd->inventory_data[sd->equip_index[2]]->view_id > 0)
+ WBUFW(buf,7)=sd->inventory_data[sd->equip_index[2]]->view_id;
+ else
+ WBUFW(buf,7)=sd->status.inventory[sd->equip_index[2]].nameid;
+ } else
+ WBUFW(buf,7)=0;
+ WBUFW(buf,9)=0;
+ }
+ else {
+ WBUFB(buf,6)=2;
+ if(sd->equip_index[9] >= 0 && sd->inventory_data[sd->equip_index[9]] && sd->view_class != 22) {
+ if(sd->inventory_data[sd->equip_index[9]]->view_id > 0)
+ WBUFW(buf,7)=sd->inventory_data[sd->equip_index[9]]->view_id;
+ else
+ WBUFW(buf,7)=sd->status.inventory[sd->equip_index[9]].nameid;
+ } else
+ WBUFW(buf,7)=0;
+ if(sd->equip_index[8] >= 0 && sd->equip_index[8] != sd->equip_index[9] && sd->inventory_data[sd->equip_index[8]] &&
+ sd->view_class != 22) {
+ if(sd->inventory_data[sd->equip_index[8]]->view_id > 0)
+ WBUFW(buf,9)=sd->inventory_data[sd->equip_index[8]]->view_id;
+ else
+ WBUFW(buf,9)=sd->status.inventory[sd->equip_index[8]].nameid;
+ } else
+ WBUFW(buf,9)=0;
+ }
+ clif_send(buf,packet_db[0x1d7].len,bl,AREA);
+ }
+ else if(sd && (type == LOOK_BASE) && (val > 255))
+ {
+ WBUFW(buf,0)=0x1d7;
+ WBUFL(buf,2)=bl->id;
+ WBUFB(buf,6)=type;
+ WBUFW(buf,7)=val;
+ WBUFW(buf,9)=0;
+ clif_send(buf,packet_db[0x1d7].len,bl,AREA);
+ } else {
+ WBUFW(buf,0)=0xc3;
+ WBUFL(buf,2)=bl->id;
+ WBUFB(buf,6)=type;
+ WBUFB(buf,7)=val;
+ clif_send(buf,packet_db[0xc3].len,bl,AREA);
+ }
+#endif
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_initialstatus(struct map_session_data *sd)
+{
+ int fd;
+ unsigned char *buf;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ buf=WFIFOP(fd,0);
+
+ WBUFW(buf,0)=0xbd;
+ WBUFW(buf,2)=sd->status.status_point;
+ WBUFB(buf,4)=(sd->status.str > 255)? 255:sd->status.str;
+ WBUFB(buf,5)=pc_need_status_point(sd,SP_STR);
+ WBUFB(buf,6)=(sd->status.agi > 255)? 255:sd->status.agi;
+ WBUFB(buf,7)=pc_need_status_point(sd,SP_AGI);
+ WBUFB(buf,8)=(sd->status.vit > 255)? 255:sd->status.vit;
+ WBUFB(buf,9)=pc_need_status_point(sd,SP_VIT);
+ WBUFB(buf,10)=(sd->status.int_ > 255)? 255:sd->status.int_;
+ WBUFB(buf,11)=pc_need_status_point(sd,SP_INT);
+ WBUFB(buf,12)=(sd->status.dex > 255)? 255:sd->status.dex;
+ WBUFB(buf,13)=pc_need_status_point(sd,SP_DEX);
+ WBUFB(buf,14)=(sd->status.luk > 255)? 255:sd->status.luk;
+ WBUFB(buf,15)=pc_need_status_point(sd,SP_LUK);
+
+ WBUFW(buf,16) = sd->base_atk + sd->watk;
+ WBUFW(buf,18) = sd->watk2; //atk bonus
+ WBUFW(buf,20) = sd->matk1;
+ WBUFW(buf,22) = sd->matk2;
+ WBUFW(buf,24) = sd->def; // def
+ WBUFW(buf,26) = sd->def2;
+ WBUFW(buf,28) = sd->mdef; // mdef
+ WBUFW(buf,30) = sd->mdef2;
+ WBUFW(buf,32) = sd->hit;
+ WBUFW(buf,34) = sd->flee;
+ WBUFW(buf,36) = sd->flee2/10;
+ WBUFW(buf,38) = sd->critical/10;
+ WBUFW(buf,40) = sd->status.karma;
+ WBUFW(buf,42) = sd->status.manner;
+
+ WFIFOSET(fd,packet_db[0xbd].len);
+
+ clif_updatestatus(sd,SP_STR);
+ clif_updatestatus(sd,SP_AGI);
+ clif_updatestatus(sd,SP_VIT);
+ clif_updatestatus(sd,SP_INT);
+ clif_updatestatus(sd,SP_DEX);
+ clif_updatestatus(sd,SP_LUK);
+
+ clif_updatestatus(sd,SP_ATTACKRANGE);
+ clif_updatestatus(sd,SP_ASPD);
+
+ return 0;
+}
+
+/*==========================================
+ *矢装備
+ *------------------------------------------
+ */
+int clif_arrowequip(struct map_session_data *sd,int val)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ if(sd->attacktarget && sd->attacktarget > 0) // [Valaris]
+ sd->attacktarget = 0;
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x013c;
+ WFIFOW(fd,2)=val+2;//矢のアイテムID
+
+ WFIFOSET(fd,packet_db[0x013c].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_arrow_fail(struct map_session_data *sd,int type)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x013b;
+ WFIFOW(fd,2)=type;
+
+ WFIFOSET(fd,packet_db[0x013b].len);
+
+ return 0;
+}
+
+/*==========================================
+ * 作成可能 矢リスト送信
+ *------------------------------------------
+ */
+int clif_arrow_create_list(struct map_session_data *sd)
+{
+ int i,c,view;
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x1ad;
+
+ for(i=0,c=0;i<MAX_SKILL_ARROW_DB;i++){
+ if(skill_arrow_db[i].nameid > 0 && pc_search_inventory(sd,skill_arrow_db[i].nameid)>=0){
+ if((view = itemdb_viewid(skill_arrow_db[i].nameid)) > 0)
+ WFIFOW(fd,c*2+4) = view;
+ else
+ WFIFOW(fd,c*2+4) = skill_arrow_db[i].nameid;
+ c++;
+ }
+ }
+ WFIFOW(fd,2)=c*2+4;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ if(c > 0) sd->state.make_arrow_flag = 1;
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_statusupack(struct map_session_data *sd,int type,int ok,int val)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xbc;
+ WFIFOW(fd,2)=type;
+ WFIFOB(fd,4)=ok;
+ WFIFOB(fd,5)=val;
+ WFIFOSET(fd,packet_db[0xbc].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_equipitemack(struct map_session_data *sd,int n,int pos,int ok)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xaa;
+ WFIFOW(fd,2)=n+2;
+ WFIFOW(fd,4)=pos;
+ WFIFOB(fd,6)=ok;
+ WFIFOSET(fd,packet_db[0xaa].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_unequipitemack(struct map_session_data *sd,int n,int pos,int ok)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xac;
+ WFIFOW(fd,2)=n+2;
+ WFIFOW(fd,4)=pos;
+ WFIFOB(fd,6)=ok;
+ WFIFOSET(fd,packet_db[0xac].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_misceffect(struct block_list* bl,int type)
+{
+ char buf[32];
+
+ nullpo_retr(0, bl);
+
+ WBUFW(buf,0) = 0x19b;
+ WBUFL(buf,2) = bl->id;
+ WBUFL(buf,6) = type;
+
+ clif_send(buf,packet_db[0x19b].len,bl,AREA);
+
+ return 0;
+}
+int clif_misceffect2(struct block_list *bl, int type) {
+ unsigned char buf[24];
+
+ nullpo_retr(0, bl);
+
+ memset(buf, 0, packet_db[0x1f3].len);
+
+ WBUFW(buf,0) = 0x1f3;
+ WBUFL(buf,2) = bl->id;
+ WBUFL(buf,6) = type;
+
+ clif_send(buf, packet_db[0x1f3].len, bl, AREA);
+
+ return 0;
+
+}
+/*==========================================
+ * 表示オプション変更
+ *------------------------------------------
+ */
+int clif_changeoption(struct block_list* bl)
+{
+ char buf[32];
+ short option;
+ struct status_change *sc_data;
+ static const int omask[]={ 0x10,0x20 };
+ static const int scnum[]={ SC_FALCON, SC_RIDING };
+ int i;
+
+ nullpo_retr(0, bl);
+
+ option = *battle_get_option(bl);
+ sc_data = battle_get_sc_data(bl);
+
+ WBUFW(buf,0) = 0x119;
+ WBUFL(buf,2) = bl->id;
+ WBUFW(buf,6) = *battle_get_opt1(bl);
+ WBUFW(buf,8) = *battle_get_opt2(bl);
+ WBUFW(buf,10) = option;
+ WBUFB(buf,12) = 0; // ??
+
+ if(bl->type==BL_PC) { // disguises [Valaris]
+ struct map_session_data *sd=((struct map_session_data *)bl);
+ if(sd && sd->disguise > 23 && sd->disguise < 4001) {
+ clif_send(buf,packet_db[0x119].len,bl,AREA_WOS);
+ clif_spawnpc(sd);
+ } else
+ clif_send(buf,packet_db[0x119].len,bl,AREA);
+ } else
+ clif_send(buf,packet_db[0x119].len,bl,AREA);
+
+ // アイコンの表示
+ for(i=0;i<sizeof(omask)/sizeof(omask[0]);i++){
+ if( option&omask[i] ){
+ if( sc_data[scnum[i]].timer==-1)
+ skill_status_change_start(bl,scnum[i],0,0,0,0,0,0);
+ } else {
+ skill_status_change_end(bl,scnum[i],-1);
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_useitemack(struct map_session_data *sd,int index,int amount,int ok)
+{
+ nullpo_retr(0, sd);
+
+ if(!ok) {
+ int fd=sd->fd;
+ WFIFOW(fd,0)=0xa8;
+ WFIFOW(fd,2)=index+2;
+ WFIFOW(fd,4)=amount;
+ WFIFOB(fd,6)=ok;
+ WFIFOSET(fd,packet_db[0xa8].len);
+ }
+ else {
+#if PACKETVER < 3
+ int fd=sd->fd;
+ WFIFOW(fd,0)=0xa8;
+ WFIFOW(fd,2)=index+2;
+ WFIFOW(fd,4)=amount;
+ WFIFOB(fd,6)=ok;
+ WFIFOSET(fd,packet_db[0xa8].len);
+#else
+ char buf[32];
+
+ WBUFW(buf,0)=0x1c8;
+ WBUFW(buf,2)=index+2;
+ if(sd->inventory_data[index] && sd->inventory_data[index]->view_id > 0)
+ WBUFW(buf,4)=sd->inventory_data[index]->view_id;
+ else
+ WBUFW(buf,4)=sd->status.inventory[index].nameid;
+ WBUFL(buf,6)=sd->bl.id;
+ WBUFW(buf,10)=amount;
+ WBUFB(buf,12)=ok;
+ clif_send(buf,packet_db[0x1c8].len,&sd->bl,AREA);
+#endif
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_createchat(struct map_session_data *sd,int fail)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xd6;
+ WFIFOB(fd,2)=fail;
+ WFIFOSET(fd,packet_db[0xd6].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_dispchat(struct chat_data *cd,int fd)
+{
+ char buf[128]; // 最大title(60バイト)+17
+
+ if(cd==NULL || *cd->owner==NULL)
+ return 1;
+
+ WBUFW(buf,0)=0xd7;
+ WBUFW(buf,2)=strlen(cd->title)+17;
+ WBUFL(buf,4)=(*cd->owner)->id;
+ WBUFL(buf,8)=cd->bl.id;
+ WBUFW(buf,12)=cd->limit;
+ WBUFW(buf,14)=cd->users;
+ WBUFB(buf,16)=cd->pub;
+ strcpy(WBUFP(buf,17),cd->title);
+ if(fd){
+ memcpy(WFIFOP(fd,0),buf,WBUFW(buf,2));
+ WFIFOSET(fd,WBUFW(buf,2));
+ } else {
+ clif_send(buf,WBUFW(buf,2),*cd->owner,AREA_WOSC);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * chatの状態変更成功
+ * 外部の人用と命令コード(d7->df)が違うだけ
+ *------------------------------------------
+ */
+int clif_changechatstatus(struct chat_data *cd)
+{
+ char buf[128]; // 最大title(60バイト)+17
+
+ if(cd==NULL || cd->usersd[0]==NULL)
+ return 1;
+
+ WBUFW(buf,0)=0xdf;
+ WBUFW(buf,2)=strlen(cd->title)+17;
+ WBUFL(buf,4)=cd->usersd[0]->bl.id;
+ WBUFL(buf,8)=cd->bl.id;
+ WBUFW(buf,12)=cd->limit;
+ WBUFW(buf,14)=cd->users;
+ WBUFB(buf,16)=cd->pub;
+ strcpy(WBUFP(buf,17),cd->title);
+ clif_send(buf,WBUFW(buf,2),&cd->usersd[0]->bl,CHAT);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_clearchat(struct chat_data *cd,int fd)
+{
+ char buf[32];
+
+ nullpo_retr(0, cd);
+
+ WBUFW(buf,0)=0xd8;
+ WBUFL(buf,2)=cd->bl.id;
+ if(fd){
+ memcpy(WFIFOP(fd,0),buf,packet_db[0xd8].len);
+ WFIFOSET(fd,packet_db[0xd8].len);
+ } else {
+ clif_send(buf,packet_db[0xd8].len,*cd->owner,AREA_WOSC);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_joinchatfail(struct map_session_data *sd,int fail)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+
+ WFIFOW(fd,0)=0xda;
+ WFIFOB(fd,2)=fail;
+ WFIFOSET(fd,packet_db[0xda].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_joinchatok(struct map_session_data *sd,struct chat_data* cd)
+{
+ int fd;
+ int i;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, cd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xdb;
+ WFIFOW(fd,2)=8+(28*cd->users);
+ WFIFOL(fd,4)=cd->bl.id;
+ for(i = 0;i < cd->users;i++){
+ WFIFOL(fd,8+i*28) = (i!=0)||((*cd->owner)->type==BL_NPC);
+ memcpy(WFIFOP(fd,8+i*28+4),cd->usersd[i]->status.name,24);
+ }
+ WFIFOSET(fd,WFIFOW(fd,2));
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_addchat(struct chat_data* cd,struct map_session_data *sd)
+{
+ char buf[32];
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, cd);
+
+ WBUFW(buf, 0) = 0x0dc;
+ WBUFW(buf, 2) = cd->users;
+ memcpy(WBUFP(buf, 4),sd->status.name,24);
+ clif_send(buf,packet_db[0xdc].len,&sd->bl,CHAT_WOS);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_changechatowner(struct chat_data* cd,struct map_session_data *sd)
+{
+ char buf[64];
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, cd);
+
+ WBUFW(buf, 0) = 0xe1;
+ WBUFL(buf, 2) = 1;
+ memcpy(WBUFP(buf,6),cd->usersd[0]->status.name,24);
+ WBUFW(buf,30) = 0xe1;
+ WBUFL(buf,32) = 0;
+ memcpy(WBUFP(buf,36),sd->status.name,24);
+
+ clif_send(buf,packet_db[0xe1].len*2,&sd->bl,CHAT);
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_leavechat(struct chat_data* cd,struct map_session_data *sd)
+{
+ char buf[32];
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, cd);
+
+ WBUFW(buf, 0) = 0xdd;
+ WBUFW(buf, 2) = cd->users-1;
+ memcpy(WBUFP(buf,4),sd->status.name,24);
+ WBUFB(buf,28) = 0;
+
+ clif_send(buf,packet_db[0xdd].len,&sd->bl,CHAT);
+
+ return 0;
+}
+
+/*==========================================
+ * 取り引き要請受け
+ *------------------------------------------
+ */
+int clif_traderequest(struct map_session_data *sd,char *name)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xe5;
+ strcpy(WFIFOP(fd,2),name);
+ WFIFOSET(fd,packet_db[0xe5].len);
+
+ return 0;
+}
+
+/*==========================================
+ * 取り引き要求応答
+ *------------------------------------------
+ */
+int clif_tradestart(struct map_session_data *sd,int type)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xe7;
+ WFIFOB(fd,2)=type;
+ WFIFOSET(fd,packet_db[0xe7].len);
+
+ return 0;
+}
+
+/*==========================================
+ * 相手方からのアイテム追加
+ *------------------------------------------
+ */
+int clif_tradeadditem(struct map_session_data *sd,struct map_session_data *tsd,int index,int amount)
+{
+ int fd,j;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, tsd);
+
+ fd=tsd->fd;
+ WFIFOW(fd,0)=0xe9;
+ WFIFOL(fd,2)=amount;
+ if(index==0){
+ WFIFOW(fd,6) = 0; // type id
+ WFIFOB(fd,8) = 0; //identify flag
+ WFIFOB(fd,9) = 0; // attribute
+ WFIFOB(fd,10)= 0; //refine
+ WFIFOW(fd,11)= 0; //card (4w)
+ WFIFOW(fd,13)= 0; //card (4w)
+ WFIFOW(fd,15)= 0; //card (4w)
+ WFIFOW(fd,17)= 0; //card (4w)
+ }
+ else{
+ index -= 2;
+ if(sd->inventory_data[index] && sd->inventory_data[index]->view_id > 0)
+ WFIFOW(fd,6) = sd->inventory_data[index]->view_id;
+ else
+ WFIFOW(fd,6) = sd->status.inventory[index].nameid; // type id
+ WFIFOB(fd,8) = sd->status.inventory[index].identify; //identify flag
+ WFIFOB(fd,9) = sd->status.inventory[index].attribute; // attribute
+ WFIFOB(fd,10)= sd->status.inventory[index].refine; //refine
+ if(sd->status.inventory[index].card[0]==0x00ff || sd->status.inventory[index].card[0]==0x00fe || sd->status.inventory[index].card[0]==(short)0xff00) {
+ WFIFOW(fd,11)= sd->status.inventory[index].card[0]; //card (4w)
+ WFIFOW(fd,13)= sd->status.inventory[index].card[1]; //card (4w)
+ WFIFOW(fd,15)= sd->status.inventory[index].card[2]; //card (4w)
+ WFIFOW(fd,17)= sd->status.inventory[index].card[3]; //card (4w)
+ } else {
+ if(sd->status.inventory[index].card[0] > 0 && (j=itemdb_viewid(sd->status.inventory[index].card[0])) > 0)
+ WFIFOW(fd,11)= j;
+ else
+ WFIFOW(fd,11)= sd->status.inventory[index].card[0];
+ if(sd->status.inventory[index].card[1] > 0 && (j=itemdb_viewid(sd->status.inventory[index].card[1])) > 0)
+ WFIFOW(fd,13)= j;
+ else
+ WFIFOW(fd,13)= sd->status.inventory[index].card[1];
+ if(sd->status.inventory[index].card[2] > 0 && (j=itemdb_viewid(sd->status.inventory[index].card[2])) > 0)
+ WFIFOW(fd,15)= j;
+ else
+ WFIFOW(fd,15)= sd->status.inventory[index].card[2];
+ if(sd->status.inventory[index].card[3] > 0 && (j=itemdb_viewid(sd->status.inventory[index].card[3])) > 0)
+ WFIFOW(fd,17)= j;
+ else
+ WFIFOW(fd,17)= sd->status.inventory[index].card[3];
+ }
+ }
+ WFIFOSET(fd,packet_db[0xe9].len);
+
+ return 0;
+}
+
+/*==========================================
+ * アイテム追加成功/失敗
+ *------------------------------------------
+ */
+int clif_tradeitemok(struct map_session_data *sd,int index,int fail)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xea;
+ WFIFOW(fd,2)=index;
+ WFIFOB(fd,4)=fail;
+ WFIFOSET(fd,packet_db[0xea].len);
+
+ return 0;
+}
+
+/*==========================================
+ * 取り引きok押し
+ *------------------------------------------
+ */
+int clif_tradedeal_lock(struct map_session_data *sd,int fail)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xec;
+ WFIFOB(fd,2)=fail; // 0=you 1=the other person
+ WFIFOSET(fd,packet_db[0xec].len);
+
+ return 0;
+}
+
+/*==========================================
+ * 取り引きがキャンセルされました
+ *------------------------------------------
+ */
+int clif_tradecancelled(struct map_session_data *sd)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xee;
+ WFIFOSET(fd,packet_db[0xee].len);
+
+ return 0;
+}
+
+/*==========================================
+ * 取り引き完了
+ *------------------------------------------
+ */
+int clif_tradecompleted(struct map_session_data *sd,int fail)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xf0;
+ WFIFOB(fd,2)=fail;
+ WFIFOSET(fd,packet_db[0xf0].len);
+
+ return 0;
+}
+
+/*==========================================
+ * カプラ倉庫のアイテム数を更新
+ *------------------------------------------
+ */
+int clif_updatestorageamount(struct map_session_data *sd,struct storage *stor)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor);
+
+ fd=sd->fd;
+ WFIFOW(fd,0) = 0xf2; // update storage amount
+ WFIFOW(fd,2) = stor->storage_amount; //items
+ WFIFOW(fd,4) = MAX_STORAGE; //items max
+ WFIFOSET(fd,packet_db[0xf2].len);
+
+ return 0;
+}
+
+/*==========================================
+ * カプラ倉庫にアイテムを追加する
+ *------------------------------------------
+ */
+int clif_storageitemadded(struct map_session_data *sd,struct storage *stor,int index,int amount)
+{
+ int view,fd,j;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor);
+
+ fd=sd->fd;
+ WFIFOW(fd,0) =0xf4; // Storage item added
+ WFIFOW(fd,2) =index+1; // index
+ WFIFOL(fd,4) =amount; // amount
+ if((view = itemdb_viewid(stor->storage[index].nameid)) > 0)
+ WFIFOW(fd,8) =view;
+ else
+ WFIFOW(fd,8) =stor->storage[index].nameid; // id
+ WFIFOB(fd,10)=stor->storage[index].identify; //identify flag
+ WFIFOB(fd,11)=stor->storage[index].attribute; // attribute
+ WFIFOB(fd,12)=stor->storage[index].refine; //refine
+ if(stor->storage[index].card[0]==0x00ff || stor->storage[index].card[0]==0x00fe || stor->storage[index].card[0]==(short)0xff00) {
+ WFIFOW(fd,13)=stor->storage[index].card[0]; //card (4w)
+ WFIFOW(fd,15)=stor->storage[index].card[1]; //card (4w)
+ WFIFOW(fd,17)=stor->storage[index].card[2]; //card (4w)
+ WFIFOW(fd,19)=stor->storage[index].card[3]; //card (4w)
+ } else {
+ if(stor->storage[index].card[0] > 0 && (j=itemdb_viewid(stor->storage[index].card[0])) > 0)
+ WFIFOW(fd,13)= j;
+ else
+ WFIFOW(fd,13)= stor->storage[index].card[0];
+ if(stor->storage[index].card[1] > 0 && (j=itemdb_viewid(stor->storage[index].card[1])) > 0)
+ WFIFOW(fd,15)= j;
+ else
+ WFIFOW(fd,15)= stor->storage[index].card[1];
+ if(stor->storage[index].card[2] > 0 && (j=itemdb_viewid(stor->storage[index].card[2])) > 0)
+ WFIFOW(fd,17)= j;
+ else
+ WFIFOW(fd,17)= stor->storage[index].card[2];
+ if(stor->storage[index].card[3] > 0 && (j=itemdb_viewid(stor->storage[index].card[3])) > 0)
+ WFIFOW(fd,19)= j;
+ else
+ WFIFOW(fd,19)= stor->storage[index].card[3];
+ }
+ WFIFOSET(fd,packet_db[0xf4].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_updateguildstorageamount(struct map_session_data *sd,struct guild_storage *stor)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor);
+
+ fd=sd->fd;
+ WFIFOW(fd,0) = 0xf2; // update storage amount
+ WFIFOW(fd,2) = stor->storage_amount; //items
+ WFIFOW(fd,4) = MAX_GUILD_STORAGE; //items max
+ WFIFOSET(fd,packet_db[0xf2].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_guildstorageitemadded(struct map_session_data *sd,struct guild_storage *stor,int index,int amount)
+{
+ int view,fd,j;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor);
+
+ fd=sd->fd;
+ WFIFOW(fd,0) =0xf4; // Storage item added
+ WFIFOW(fd,2) =index+1; // index
+ WFIFOL(fd,4) =amount; // amount
+ if((view = itemdb_viewid(stor->storage[index].nameid)) > 0)
+ WFIFOW(fd,8) =view;
+ else
+ WFIFOW(fd,8) =stor->storage[index].nameid; // id
+ WFIFOB(fd,10)=stor->storage[index].identify; //identify flag
+ WFIFOB(fd,11)=stor->storage[index].attribute; // attribute
+ WFIFOB(fd,12)=stor->storage[index].refine; //refine
+ if(stor->storage[index].card[0]==0x00ff || stor->storage[index].card[0]==0x00fe || stor->storage[index].card[0]==(short)0xff00) {
+ WFIFOW(fd,13)=stor->storage[index].card[0]; //card (4w)
+ WFIFOW(fd,15)=stor->storage[index].card[1]; //card (4w)
+ WFIFOW(fd,17)=stor->storage[index].card[2]; //card (4w)
+ WFIFOW(fd,19)=stor->storage[index].card[3]; //card (4w)
+ } else {
+ if(stor->storage[index].card[0] > 0 && (j=itemdb_viewid(stor->storage[index].card[0])) > 0)
+ WFIFOW(fd,13)= j;
+ else
+ WFIFOW(fd,13)= stor->storage[index].card[0];
+ if(stor->storage[index].card[1] > 0 && (j=itemdb_viewid(stor->storage[index].card[1])) > 0)
+ WFIFOW(fd,15)= j;
+ else
+ WFIFOW(fd,15)= stor->storage[index].card[1];
+ if(stor->storage[index].card[2] > 0 && (j=itemdb_viewid(stor->storage[index].card[2])) > 0)
+ WFIFOW(fd,17)= j;
+ else
+ WFIFOW(fd,17)= stor->storage[index].card[2];
+ if(stor->storage[index].card[3] > 0 && (j=itemdb_viewid(stor->storage[index].card[3])) > 0)
+ WFIFOW(fd,19)= j;
+ else
+ WFIFOW(fd,19)= stor->storage[index].card[3];
+ }
+ WFIFOSET(fd,packet_db[0xf4].len);
+
+ return 0;
+}
+
+/*==========================================
+ * カプラ倉庫からアイテムを取り去る
+ *------------------------------------------
+ */
+int clif_storageitemremoved(struct map_session_data *sd,int index,int amount)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xf6; // Storage item removed
+ WFIFOW(fd,2)=index+1;
+ WFIFOL(fd,4)=amount;
+ WFIFOSET(fd,packet_db[0xf6].len);
+
+ return 0;
+}
+
+/*==========================================
+ * カプラ倉庫を閉じる
+ *------------------------------------------
+ */
+int clif_storageclose(struct map_session_data *sd)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xf8; // Storage Closed
+ WFIFOSET(fd,packet_db[0xf8].len);
+
+ return 0;
+}
+
+//
+// callback系 ?
+//
+/*==========================================
+ * PC表示
+ *------------------------------------------
+ */
+void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* dstsd)
+{
+ int len;
+
+ nullpo_retv(sd);
+ nullpo_retv(dstsd);
+
+ if(dstsd->walktimer != -1){
+ len = clif_set007b(dstsd,WFIFOP(sd->fd,0));
+ WFIFOSET(sd->fd,len);
+ } else {
+ len = clif_set0078(dstsd,WFIFOP(sd->fd,0));
+ WFIFOSET(sd->fd,len);
+ }
+
+ if(dstsd->chatID){
+ struct chat_data *cd;
+ cd=(struct chat_data*)map_id2bl(dstsd->chatID);
+ if(cd->usersd[0]==dstsd)
+ clif_dispchat(cd,sd->fd);
+ }
+ if(dstsd->vender_id){
+ clif_showvendingboard(&dstsd->bl,dstsd->message,sd->fd);
+ }
+ if(dstsd->spiritball > 0) {
+ clif_set01e1(dstsd,WFIFOP(sd->fd,0));
+ WFIFOSET(sd->fd,packet_db[0x1e1].len);
+ }
+ if(battle_config.save_clothcolor==1 && dstsd->status.clothes_color > 0)
+ clif_changelook(&dstsd->bl,LOOK_CLOTHES_COLOR,dstsd->status.clothes_color);
+
+ if(sd->status.manner < 0)
+ clif_changestatus(&sd->bl,SP_MANNER,sd->status.manner);
+
+}
+
+/*==========================================
+ * NPC表示
+ *------------------------------------------
+ */
+void clif_getareachar_npc(struct map_session_data* sd,struct npc_data* nd)
+{
+ int len;
+
+ nullpo_retv(sd);
+ nullpo_retv(nd);
+
+ if(nd->class < 0 || nd->flag&1 || nd->class == INVISIBLE_CLASS)
+ return;
+
+ len = clif_npc0078(nd,WFIFOP(sd->fd,0));
+ WFIFOSET(sd->fd,len);
+
+ if(nd->chat_id){
+ clif_dispchat((struct chat_data*)map_id2bl(nd->chat_id),sd->fd);
+ }
+
+}
+
+/*==========================================
+ * 移動停止
+ *------------------------------------------
+ */
+int clif_movemob(struct mob_data *md)
+{
+ unsigned char buf[256];
+ int len;
+
+ nullpo_retr(0, md);
+
+ len = clif_mob007b(md,buf);
+ clif_send(buf,len,&md->bl,AREA);
+
+ if(mob_get_equip(md->class) > 0) // mob equipment [Valaris]
+ clif_mob_equip(md,mob_get_equip(md->class));
+
+ return 0;
+}
+
+/*==========================================
+ * モンスターの位置修正
+ *------------------------------------------
+ */
+int clif_fixmobpos(struct mob_data *md)
+{
+ unsigned char buf[256];
+ int len;
+
+ nullpo_retr(0, md);
+
+ if(md->state.state == MS_WALK){
+ len = clif_mob007b(md,buf);
+ clif_send(buf,len,&md->bl,AREA);
+ } else {
+ len = clif_mob0078(md,buf);
+ clif_send(buf,len,&md->bl,AREA);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * PCの位置修正
+ *------------------------------------------
+ */
+int clif_fixpcpos(struct map_session_data *sd)
+{
+ unsigned char buf[256];
+ int len;
+
+ nullpo_retr(0, sd);
+
+ if(sd->walktimer != -1){
+ len = clif_set007b(sd,buf);
+ clif_send(buf,len,&sd->bl,AREA);
+ } else {
+ len = clif_set0078(sd,buf);
+ clif_send(buf,len,&sd->bl,AREA);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_fixpetpos(struct pet_data *pd)
+{
+ unsigned char buf[256];
+ int len;
+
+ nullpo_retr(0, pd);
+
+ if(pd->state.state == MS_WALK){
+ len = clif_pet007b(pd,buf);
+ clif_send(buf,len,&pd->bl,AREA);
+ } else {
+ len = clif_pet0078(pd,buf);
+ clif_send(buf,len,&pd->bl,AREA);
+ }
+
+ return 0;
+}
+
+// npc walking [Valaris]
+int clif_fixnpcpos(struct npc_data *nd)
+{
+ unsigned char buf[256];
+ int len;
+
+ nullpo_retr(0, nd);
+
+ if(nd->state.state == MS_WALK){
+ len = clif_npc007b(nd,buf);
+ clif_send(buf,len,&nd->bl,AREA);
+ } else {
+ len = clif_npc0078(nd,buf);
+ clif_send(buf,len,&nd->bl,AREA);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 通常攻撃エフェクト&ダメージ
+ *------------------------------------------
+ */
+int clif_damage(struct block_list *src,struct block_list *dst,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2)
+{
+ unsigned char buf[256];
+ struct status_change *sc_data;
+
+ nullpo_retr(0, src);
+ nullpo_retr(0, dst);
+
+ sc_data = battle_get_sc_data(dst);
+
+ if(type != 4 && dst->type == BL_PC && ((struct map_session_data *)dst)->special_state.infinite_endure)
+ type = 9;
+ if(sc_data) {
+ if(type != 4 && sc_data[SC_ENDURE].timer != -1)
+ type = 9;
+ if(sc_data[SC_HALLUCINATION].timer != -1) {
+ if(damage > 0)
+ damage = damage*(5+sc_data[SC_HALLUCINATION].val1) + rand()%100;
+ if(damage2 > 0)
+ damage2 = damage2*(5+sc_data[SC_HALLUCINATION].val1) + rand()%100;
+ }
+ }
+
+ WBUFW(buf,0)=0x8a;
+ WBUFL(buf,2)=src->id;
+ WBUFL(buf,6)=dst->id;
+ WBUFL(buf,10)=tick;
+ WBUFL(buf,14)=sdelay;
+ WBUFL(buf,18)=ddelay;
+ WBUFW(buf,22)=(damage > 0x7fff)? 0x7fff:damage;
+ WBUFW(buf,24)=div;
+ WBUFB(buf,26)=type;
+ WBUFW(buf,27)=damage2;
+ clif_send(buf,packet_db[0x8a].len,src,AREA);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_getareachar_mob(struct map_session_data* sd,struct mob_data* md)
+{
+ int len;
+ nullpo_retv(sd);
+ nullpo_retv(md);
+
+ if(md->state.state == MS_WALK){
+ len = clif_mob007b(md,WFIFOP(sd->fd,0));
+ WFIFOSET(sd->fd,len);
+ } else {
+ len = clif_mob0078(md,WFIFOP(sd->fd,0));
+ WFIFOSET(sd->fd,len);
+ }
+
+ if(mob_get_equip(md->class) > 0) // mob equipment [Valaris]
+ clif_mob_equip(md,mob_get_equip(md->class));
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_getareachar_pet(struct map_session_data* sd,struct pet_data* pd)
+{
+ int len;
+
+ nullpo_retv(sd);
+ nullpo_retv(pd);
+
+ if(pd->state.state == MS_WALK){
+ len = clif_pet007b(pd,WFIFOP(sd->fd,0));
+ WFIFOSET(sd->fd,len);
+ } else {
+ len = clif_pet0078(pd,WFIFOP(sd->fd,0));
+ WFIFOSET(sd->fd,len);
+ }
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_getareachar_item(struct map_session_data* sd,struct flooritem_data* fitem)
+{
+ int view,fd;
+
+ nullpo_retv(sd);
+ nullpo_retv(fitem);
+
+ fd=sd->fd;
+ //009d <ID>.l <item ID>.w <identify flag>.B <X>.w <Y>.w <amount>.w <subX>.B <subY>.B
+ WFIFOW(fd,0)=0x9d;
+ WFIFOL(fd,2)=fitem->bl.id;
+ if((view = itemdb_viewid(fitem->item_data.nameid)) > 0)
+ WFIFOW(fd,6)=view;
+ else
+ WFIFOW(fd,6)=fitem->item_data.nameid;
+ WFIFOB(fd,8)=fitem->item_data.identify;
+ WFIFOW(fd,9)=fitem->bl.x;
+ WFIFOW(fd,11)=fitem->bl.y;
+ WFIFOW(fd,13)=fitem->item_data.amount;
+ WFIFOB(fd,15)=fitem->subx;
+ WFIFOB(fd,16)=fitem->suby;
+
+ WFIFOSET(fd,packet_db[0x9d].len);
+}
+/*==========================================
+ * 場所スキルエフェクトが視界に入る
+ *------------------------------------------
+ */
+int clif_getareachar_skillunit(struct map_session_data *sd,struct skill_unit *unit)
+{
+ int fd;
+ struct block_list *bl;
+
+ nullpo_retr(0, unit);
+
+ fd=sd->fd;
+ bl=map_id2bl(unit->group->src_id);
+#if PACKETVER < 3
+ memset(WFIFOP(fd,0),0,packet_db[0x11f].len);
+ WFIFOW(fd, 0)=0x11f;
+ WFIFOL(fd, 2)=unit->bl.id;
+ WFIFOL(fd, 6)=unit->group->src_id;
+ WFIFOW(fd,10)=unit->bl.x;
+ WFIFOW(fd,12)=unit->bl.y;
+ WFIFOB(fd,14)=unit->group->unit_id;
+ WFIFOB(fd,15)=0;
+ WFIFOSET(fd,packet_db[0x11f].len);
+#else
+ memset(WFIFOP(fd,0),0,packet_db[0x1c9].len);
+ WFIFOW(fd, 0)=0x1c9;
+ WFIFOL(fd, 2)=unit->bl.id;
+ WFIFOL(fd, 6)=unit->group->src_id;
+ WFIFOW(fd,10)=unit->bl.x;
+ WFIFOW(fd,12)=unit->bl.y;
+ WFIFOB(fd,14)=unit->group->unit_id;
+ WFIFOB(fd,15)=1;
+ WFIFOL(fd,15+1)=0; //1-4調べた限り固定
+ WFIFOL(fd,15+5)=0; //5-8調べた限り固定
+ //9-12マップごとで一定の77-80とはまた違う4バイトのかなり大きな数字
+ WFIFOL(fd,15+13)=unit->bl.y - 0x12; //13-16ユニットのY座標-18っぽい(Y:17でFF FF FF FF)
+ WFIFOL(fd,15+17)=0x004f37dd; //17-20調べた限り固定
+ WFIFOL(fd,15+21)=0x0012f674; //21-24調べた限り固定
+ WFIFOL(fd,15+25)=0x0012f664; //25-28調べた限り固定
+ WFIFOL(fd,15+29)=0x0012f654; //29-32調べた限り固定
+ WFIFOL(fd,15+33)=0x77527bbc; //33-36調べた限り固定
+ //37-39
+ WFIFOB(fd,15+40)=0x2d; //40調べた限り固定
+ WFIFOL(fd,15+41)=0; //41-44調べた限り0固定
+ WFIFOL(fd,15+45)=0; //45-48調べた限り0固定
+ WFIFOL(fd,15+49)=0; //49-52調べた限り0固定
+ WFIFOL(fd,15+53)=0x0048d919; //53-56調べた限り固定
+ WFIFOL(fd,15+57)=0x0000003e; //57-60調べた限り固定
+ WFIFOL(fd,15+61)=0x0012f66c; //61-64調べた限り固定
+ //65-68
+ //69-72
+ if(bl) WFIFOL(fd,15+73)=bl->y; //73-76術者のY座標
+ WFIFOL(fd,15+77)=unit->bl.m; //77-80マップIDかなぁ?かなり2バイトで足りそうな数字
+ WFIFOB(fd,15+81)=0xaa; //81終端文字0xaa
+
+ /* Graffiti [Valaris] */
+ if(unit->group->unit_id==0xb0) {
+ WFIFOL(fd,15)=1;
+ WFIFOL(fd,16)=1;
+ memcpy(WFIFOP(fd,17),unit->group->valstr,80);
+ }
+
+ WFIFOSET(fd,packet_db[0x1c9].len);
+#endif
+ if(unit->group->skill_id == WZ_ICEWALL)
+ clif_set0192(fd,unit->bl.m,unit->bl.x,unit->bl.y,5);
+
+ return 0;
+}
+/*==========================================
+ * 場所スキルエフェクトが視界から消える
+ *------------------------------------------
+ */
+int clif_clearchar_skillunit(struct skill_unit *unit,int fd)
+{
+ nullpo_retr(0, unit);
+
+ WFIFOW(fd, 0)=0x120;
+ WFIFOL(fd, 2)=unit->bl.id;
+ WFIFOSET(fd,packet_db[0x120].len);
+ if(unit->group->skill_id == WZ_ICEWALL)
+ clif_set0192(fd,unit->bl.m,unit->bl.x,unit->bl.y,unit->val2);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_01ac(struct block_list *bl)
+{
+ char buf[32];
+
+ nullpo_retr(0, bl);
+
+ WBUFW(buf, 0) = 0x1ac;
+ WBUFL(buf, 2) = bl->id;
+
+ clif_send(buf,packet_db[0x1ac].len,bl,AREA);
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+ int clif_getareachar(struct block_list* bl,va_list ap)
+{
+ struct map_session_data *sd;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+
+ sd=va_arg(ap,struct map_session_data*);
+
+ switch(bl->type){
+ case BL_PC:
+ if(sd==(struct map_session_data*)bl)
+ break;
+ clif_getareachar_pc(sd,(struct map_session_data*) bl);
+ break;
+ case BL_NPC:
+ clif_getareachar_npc(sd,(struct npc_data*) bl);
+ break;
+ case BL_MOB:
+ clif_getareachar_mob(sd,(struct mob_data*) bl);
+ break;
+ case BL_PET:
+ clif_getareachar_pet(sd,(struct pet_data*) bl);
+ break;
+ case BL_ITEM:
+ clif_getareachar_item(sd,(struct flooritem_data*) bl);
+ break;
+ case BL_SKILL:
+ clif_getareachar_skillunit(sd,(struct skill_unit *)bl);
+ break;
+ default:
+ if(battle_config.error_log)
+ printf("get area char ??? %d\n",bl->type);
+ break;
+ }
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_pcoutsight(struct block_list *bl,va_list ap)
+{
+ struct map_session_data *sd,*dstsd;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, sd=va_arg(ap,struct map_session_data*));
+
+ switch(bl->type){
+ case BL_PC:
+ dstsd = (struct map_session_data*) bl;
+ if(sd != dstsd) {
+ clif_clearchar_id(dstsd->bl.id,0,sd->fd);
+ clif_clearchar_id(sd->bl.id,0,dstsd->fd);
+ if(dstsd->chatID){
+ struct chat_data *cd;
+ cd=(struct chat_data*)map_id2bl(dstsd->chatID);
+ if(cd->usersd[0]==dstsd)
+ clif_dispchat(cd,sd->fd);
+ }
+ if(dstsd->vender_id){
+ clif_closevendingboard(&dstsd->bl,sd->fd);
+ }
+ }
+ break;
+ case BL_NPC:
+ if( ((struct npc_data *)bl)->class != INVISIBLE_CLASS )
+ clif_clearchar_id(bl->id,0,sd->fd);
+ break;
+ case BL_MOB:
+ case BL_PET:
+ clif_clearchar_id(bl->id,0,sd->fd);
+ break;
+ case BL_ITEM:
+ clif_clearflooritem((struct flooritem_data*)bl,sd->fd);
+ break;
+ case BL_SKILL:
+ clif_clearchar_skillunit((struct skill_unit *)bl,sd->fd);
+ break;
+ }
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_pcinsight(struct block_list *bl,va_list ap)
+{
+ struct map_session_data *sd,*dstsd;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, sd=va_arg(ap,struct map_session_data*));
+
+ switch(bl->type){
+ case BL_PC:
+ dstsd = (struct map_session_data *)bl;
+ if(sd != dstsd) {
+ clif_getareachar_pc(sd,dstsd);
+ clif_getareachar_pc(dstsd,sd);
+ }
+ break;
+ case BL_NPC:
+ clif_getareachar_npc(sd,(struct npc_data*)bl);
+ break;
+ case BL_MOB:
+ clif_getareachar_mob(sd,(struct mob_data*)bl);
+ break;
+ case BL_PET:
+ clif_getareachar_pet(sd,(struct pet_data*)bl);
+ break;
+ case BL_ITEM:
+ clif_getareachar_item(sd,(struct flooritem_data*)bl);
+ break;
+ case BL_SKILL:
+ clif_getareachar_skillunit(sd,(struct skill_unit *)bl);
+ break;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_moboutsight(struct block_list *bl,va_list ap)
+{
+ struct map_session_data *sd;
+ struct mob_data *md;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, md=va_arg(ap,struct mob_data*));
+
+ if(bl->type==BL_PC && (sd = (struct map_session_data*) bl)){
+ clif_clearchar_id(md->bl.id,0,sd->fd);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_mobinsight(struct block_list *bl,va_list ap)
+{
+ struct map_session_data *sd;
+ struct mob_data *md;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+
+ md=va_arg(ap,struct mob_data*);
+ if(bl->type==BL_PC && (sd = (struct map_session_data *)bl)){
+ clif_getareachar_mob(sd,md);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_petoutsight(struct block_list *bl,va_list ap)
+{
+ struct map_session_data *sd;
+ struct pet_data *pd;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, pd=va_arg(ap,struct pet_data*));
+
+ if(bl->type==BL_PC && (sd = (struct map_session_data*) bl)){
+ clif_clearchar_id(pd->bl.id,0,sd->fd);
+ }
+
+ return 0;
+}
+// npc walking [Valaris]
+int clif_npcoutsight(struct block_list *bl,va_list ap)
+{
+ struct map_session_data *sd;
+ struct npc_data *nd;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, nd=va_arg(ap,struct npc_data*));
+
+ if(bl->type==BL_PC && (sd = (struct map_session_data*) bl)){
+ clif_clearchar_id(nd->bl.id,0,sd->fd);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_petinsight(struct block_list *bl,va_list ap)
+{
+ struct map_session_data *sd;
+ struct pet_data *pd;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+
+ pd=va_arg(ap,struct pet_data*);
+ if(bl->type==BL_PC && (sd = (struct map_session_data *)bl)){
+ clif_getareachar_pet(sd,pd);
+ }
+
+ return 0;
+}
+// npc walking [Valaris]
+int clif_npcinsight(struct block_list *bl,va_list ap)
+{
+ struct map_session_data *sd;
+ struct npc_data *nd;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+
+ nd=va_arg(ap,struct npc_data*);
+ if(bl->type==BL_PC && (sd = (struct map_session_data *)bl)){
+ clif_getareachar_npc(sd,nd);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_skillinfo(struct map_session_data *sd,int skillid,int type,int range)
+{
+ int fd,id;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ if( (id=sd->status.skill[skillid].id) <= 0 )
+ return 0;
+ WFIFOW(fd,0)=0x147;
+ WFIFOW(fd,2) = id;
+ if(type < 0)
+ WFIFOW(fd,4) = skill_get_inf(id);
+ else
+ WFIFOW(fd,4) = type;
+ WFIFOW(fd,6) = 0;
+ WFIFOW(fd,8) = sd->status.skill[skillid].lv;
+ WFIFOW(fd,10) = skill_get_sp(id,sd->status.skill[skillid].lv);
+ if(range < 0) {
+ range = skill_get_range(id,sd->status.skill[skillid].lv);
+ if(range < 0)
+ range = battle_get_range(&sd->bl) - (range + 1);
+ WFIFOW(fd,12)= range;
+ } else
+ WFIFOW(fd,12)= range;
+ memset(WFIFOP(fd,14),0,24);
+ if(!(skill_get_inf2(id)&0x01) || battle_config.quest_skill_learn == 1 || (battle_config.gm_allskill > 0 && pc_isGM(sd) >= battle_config.gm_allskill) )
+ WFIFOB(fd,38)= (sd->status.skill[skillid].lv < skill_get_max(id) && sd->status.skill[skillid].flag ==0 )? 1:0;
+ else
+ WFIFOB(fd,38) = 0;
+ WFIFOSET(fd,packet_db[0x147].len);
+
+ return 0;
+}
+
+/*==========================================
+ * スキルリストを送信する
+ *------------------------------------------
+ */
+int clif_skillinfoblock(struct map_session_data *sd)
+{
+ int fd;
+ int i,c,len=4,id,range;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x10f;
+ for ( i = c = 0; i < MAX_SKILL; i++){
+ if( (id=sd->status.skill[i].id)!=0 ){
+ WFIFOW(fd,len ) = id;
+ WFIFOW(fd,len+2) = skill_get_inf(id);
+ WFIFOW(fd,len+4) = 0;
+ WFIFOW(fd,len+6) = sd->status.skill[i].lv;
+ WFIFOW(fd,len+8) = skill_get_sp(id,sd->status.skill[i].lv);
+ range = skill_get_range(id,sd->status.skill[i].lv);
+ if(range < 0)
+ range = battle_get_range(&sd->bl) - (range + 1);
+ WFIFOW(fd,len+10)= range;
+ memset(WFIFOP(fd,len+12),0,24);
+ if(!(skill_get_inf2(id)&0x01) || battle_config.quest_skill_learn == 1 || (battle_config.gm_allskill > 0 && pc_isGM(sd) >= battle_config.gm_allskill) )
+ WFIFOB(fd,len+36)= (sd->status.skill[i].lv < skill_get_max(id) && sd->status.skill[i].flag ==0 )? 1:0;
+ else
+ WFIFOB(fd,len+36) = 0;
+ len+=37;
+ c++;
+ }
+ }
+ WFIFOW(fd,2)=len;
+ WFIFOSET(fd,len);
+
+ return 0;
+}
+
+/*==========================================
+ * スキル割り振り通知
+ *------------------------------------------
+ */
+int clif_skillup(struct map_session_data *sd,int skill_num)
+{
+ int range,fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0) = 0x10e;
+ WFIFOW(fd,2) = skill_num;
+ WFIFOW(fd,4) = sd->status.skill[skill_num].lv;
+ WFIFOW(fd,6) = skill_get_sp(skill_num,sd->status.skill[skill_num].lv);
+ range = skill_get_range(skill_num,sd->status.skill[skill_num].lv);
+ if(range < 0)
+ range = battle_get_range(&sd->bl) - (range + 1);
+ WFIFOW(fd,8) = range;
+ WFIFOB(fd,10) = (sd->status.skill[skill_num].lv < skill_get_max(sd->status.skill[skill_num].id)) ? 1 : 0;
+ WFIFOSET(fd,packet_db[0x10e].len);
+
+ return 0;
+}
+
+/*==========================================
+ * スキル詠唱エフェクトを送信する
+ *------------------------------------------
+ */
+int clif_skillcasting(struct block_list* bl,
+ int src_id,int dst_id,int dst_x,int dst_y,int skill_num,int casttime)
+{
+ unsigned char buf[32];
+ WBUFW(buf,0) = 0x13e;
+ 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) = skill_get_pl(skill_num);//属性
+ WBUFL(buf,20) = casttime;//skill詠唱時間
+ clif_send(buf,packet_db[0x13e].len, bl, AREA);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_skillcastcancel(struct block_list* bl)
+{
+ unsigned char buf[16];
+
+ nullpo_retr(0, bl);
+
+ WBUFW(buf,0) = 0x1b9;
+ WBUFL(buf,2) = bl->id;
+ clif_send(buf,packet_db[0x1b9].len, bl, AREA);
+
+ return 0;
+}
+
+/*==========================================
+ * スキル詠唱失敗
+ *------------------------------------------
+ */
+int clif_skill_fail(struct map_session_data *sd,int skill_id,int type,int btype)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+
+ if(type==0x4 && battle_config.display_delay_skill_fail==0){
+ return 0;
+ }
+
+ WFIFOW(fd,0) = 0x110;
+ WFIFOW(fd,2) = skill_id;
+ WFIFOW(fd,4) = btype;
+ WFIFOW(fd,6) = 0;
+ WFIFOB(fd,8) = 0;
+ WFIFOB(fd,9) = type;
+ WFIFOSET(fd,packet_db[0x110].len);
+
+ return 0;
+}
+
+/*==========================================
+ * スキル攻撃エフェクト&ダメージ
+ *------------------------------------------
+ */
+int clif_skill_damage(struct block_list *src,struct block_list *dst,
+ unsigned int tick,int sdelay,int ddelay,int damage,int div,int skill_id,int skill_lv,int type)
+{
+ unsigned char buf[64];
+ struct status_change *sc_data;
+
+ nullpo_retr(0, src);
+ nullpo_retr(0, dst);
+
+ sc_data = battle_get_sc_data(dst);
+
+ if(type != 5 && dst->type == BL_PC && ((struct map_session_data *)dst)->special_state.infinite_endure)
+ type = 9;
+ if(sc_data) {
+ if(type != 5 && sc_data[SC_ENDURE].timer != -1)
+ type = 9;
+ if(sc_data[SC_HALLUCINATION].timer != -1 && damage > 0)
+ damage = damage*(5+sc_data[SC_HALLUCINATION].val1) + rand()%100;
+ }
+
+#if PACKETVER < 3
+ WBUFW(buf,0)=0x114;
+ WBUFW(buf,2)=skill_id;
+ WBUFL(buf,4)=src->id;
+ WBUFL(buf,8)=dst->id;
+ WBUFL(buf,12)=tick;
+ WBUFL(buf,16)=sdelay;
+ WBUFL(buf,20)=ddelay;
+ WBUFW(buf,24)=damage;
+ WBUFW(buf,26)=skill_lv;
+ WBUFW(buf,28)=div;
+ WBUFB(buf,30)=(type>0)?type:skill_get_hit(skill_id);
+ clif_send(buf,packet_db[0x114].len,src,AREA);
+#else
+ WBUFW(buf,0)=0x1de;
+ WBUFW(buf,2)=skill_id;
+ WBUFL(buf,4)=src->id;
+ WBUFL(buf,8)=dst->id;
+ WBUFL(buf,12)=tick;
+ WBUFL(buf,16)=sdelay;
+ WBUFL(buf,20)=ddelay;
+ WBUFL(buf,24)=damage;
+ WBUFW(buf,28)=skill_lv;
+ WBUFW(buf,30)=div;
+ WBUFB(buf,32)=(type>0)?type:skill_get_hit(skill_id);
+ clif_send(buf,packet_db[0x1de].len,src,AREA);
+#endif
+
+ return 0;
+}
+
+/*==========================================
+ * 吹き飛ばしスキル攻撃エフェクト&ダメージ
+ *------------------------------------------
+ */
+int clif_skill_damage2(struct block_list *src,struct block_list *dst,
+ unsigned int tick,int sdelay,int ddelay,int damage,int div,int skill_id,int skill_lv,int type)
+{
+ unsigned char buf[64];
+ struct status_change *sc_data;
+
+ nullpo_retr(0, src);
+ nullpo_retr(0, dst);
+
+ sc_data = battle_get_sc_data(dst);
+
+ if(type != 5 && dst->type == BL_PC && ((struct map_session_data *)dst)->special_state.infinite_endure)
+ type = 9;
+ if(sc_data) {
+ if(type != 5 && sc_data[SC_ENDURE].timer != -1)
+ type = 9;
+ if(sc_data[SC_HALLUCINATION].timer != -1 && damage > 0)
+ damage = damage*(5+sc_data[SC_HALLUCINATION].val1) + rand()%100;
+ }
+
+ WBUFW(buf,0)=0x115;
+ WBUFW(buf,2)=skill_id;
+ WBUFL(buf,4)=src->id;
+ WBUFL(buf,8)=dst->id;
+ WBUFL(buf,12)=tick;
+ WBUFL(buf,16)=sdelay;
+ WBUFL(buf,20)=ddelay;
+ WBUFW(buf,24)=dst->x;
+ WBUFW(buf,26)=dst->y;
+ WBUFW(buf,28)=damage;
+ WBUFW(buf,30)=skill_lv;
+ WBUFW(buf,32)=div;
+ WBUFB(buf,34)=(type>0)?type:skill_get_hit(skill_id);
+ clif_send(buf,packet_db[0x115].len,src,AREA);
+
+ return 0;
+}
+
+/*==========================================
+ * 支援/回復スキルエフェクト
+ *------------------------------------------
+ */
+int clif_skill_nodamage(struct block_list *src,struct block_list *dst,
+ int skill_id,int heal,int fail)
+{
+ unsigned char buf[32];
+
+ nullpo_retr(0, src);
+ nullpo_retr(0, dst);
+
+ WBUFW(buf,0)=0x11a;
+ WBUFW(buf,2)=skill_id;
+ WBUFW(buf,4)=(heal > 0x7fff)? 0x7fff:heal;
+ WBUFL(buf,6)=dst->id;
+ WBUFL(buf,10)=src->id;
+ WBUFB(buf,14)=fail;
+ clif_send(buf,packet_db[0x11a].len,src,AREA);
+
+ return 0;
+}
+
+/*==========================================
+ * 場所スキルエフェクト
+ *------------------------------------------
+ */
+int clif_skill_poseffect(struct block_list *src,int skill_id,int val,int x,int y,int tick)
+{
+ unsigned char buf[32];
+
+ nullpo_retr(0, src);
+
+ WBUFW(buf,0)=0x117;
+ WBUFW(buf,2)=skill_id;
+ WBUFL(buf,4)=src->id;
+ WBUFW(buf,8)=val;
+ WBUFW(buf,10)=x;
+ WBUFW(buf,12)=y;
+ WBUFL(buf,14)=tick;
+ clif_send(buf,packet_db[0x117].len,src,AREA);
+
+ return 0;
+}
+
+/*==========================================
+ * 場所スキルエフェクト表示
+ *------------------------------------------
+ */
+int clif_skill_setunit(struct skill_unit *unit)
+{
+ unsigned char buf[128];
+ struct block_list *bl;
+
+ nullpo_retr(0, unit);
+
+ bl=map_id2bl(unit->group->src_id);
+
+#if PACKETVER < 3
+ memset(WBUFP(buf, 0),0,packet_db[0x11f].len);
+ WBUFW(buf, 0)=0x11f;
+ WBUFL(buf, 2)=unit->bl.id;
+ WBUFL(buf, 6)=unit->group->src_id;
+ WBUFW(buf,10)=unit->bl.x;
+ WBUFW(buf,12)=unit->bl.y;
+ WBUFB(buf,14)=unit->group->unit_id;
+ WBUFB(buf,15)=0;
+ clif_send(buf,packet_db[0x11f].len,&unit->bl,AREA);
+#else
+ memset(WBUFP(buf, 0),0,packet_db[0x1c9].len);
+ WBUFW(buf, 0)=0x1c9;
+ WBUFL(buf, 2)=unit->bl.id;
+ WBUFL(buf, 6)=unit->group->src_id;
+ WBUFW(buf,10)=unit->bl.x;
+ WBUFW(buf,12)=unit->bl.y;
+ WBUFB(buf,14)=unit->group->unit_id;
+ WBUFB(buf,15)=1;
+ WBUFL(buf,15+1)=0; //1-4調べた限り固定
+ WBUFL(buf,15+5)=0; //5-8調べた限り固定
+ //9-12マップごとで一定の77-80とはまた違う4バイトのかなり大きな数字
+ WBUFL(buf,15+13)=unit->bl.y - 0x12; //13-16ユニットのY座標-18っぽい(Y:17でFF FF FF FF)
+ WBUFL(buf,15+17)=0x004f37dd; //17-20調べた限り固定(0x1b2で0x004fdbddだった)
+ WBUFL(buf,15+21)=0x0012f674; //21-24調べた限り固定
+ WBUFL(buf,15+25)=0x0012f664; //25-28調べた限り固定
+ WBUFL(buf,15+29)=0x0012f654; //29-32調べた限り固定
+ WBUFL(buf,15+33)=0x77527bbc; //33-36調べた限り固定
+ //37-39
+ WBUFB(buf,15+40)=0x2d; //40調べた限り固定
+ WBUFL(buf,15+41)=0; //41-44調べた限り0固定
+ WBUFL(buf,15+45)=0; //45-48調べた限り0固定
+ WBUFL(buf,15+49)=0; //49-52調べた限り0固定
+ WBUFL(buf,15+53)=0x0048d919; //53-56調べた限り固定(0x01b2で0x00495119だった)
+ WBUFL(buf,15+57)=0x0000003e; //57-60調べた限り固定
+ WBUFL(buf,15+61)=0x0012f66c; //61-64調べた限り固定
+ //65-68
+ //69-72
+ if(bl) WBUFL(buf,15+73)=bl->y; //73-76術者のY座標
+ WBUFL(buf,15+77)=unit->bl.m; //77-80マップIDかなぁ?かなり2バイトで足りそうな数字
+ WBUFB(buf,15+81)=0xaa; //81終端文字0xaa
+
+ /* Graffiti [Valaris] */
+ if(unit->group->unit_id==0xb0) {
+ WBUFL(buf,15)=1;
+ WBUFL(buf,16)=1;
+ memcpy(WBUFP(buf,17),unit->group->valstr,80);
+ }
+
+ clif_send(buf,packet_db[0x1c9].len,&unit->bl,AREA);
+#endif
+ return 0;
+}
+/*==========================================
+ * 場所スキルエフェクト削除
+ *------------------------------------------
+ */
+int clif_skill_delunit(struct skill_unit *unit)
+{
+ unsigned char buf[16];
+
+ nullpo_retr(0, unit);
+
+ WBUFW(buf, 0)=0x120;
+ WBUFL(buf, 2)=unit->bl.id;
+ clif_send(buf,packet_db[0x120].len,&unit->bl,AREA);
+ return 0;
+}
+/*==========================================
+ * ワープ場所選択
+ *------------------------------------------
+ */
+int clif_skill_warppoint(struct map_session_data *sd,int skill_num,
+ const char *map1,const char *map2,const char *map3,const char *map4)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x11c;
+ WFIFOW(fd,2)=skill_num;
+ memcpy(WFIFOP(fd, 4),map1,16);
+ memcpy(WFIFOP(fd,20),map2,16);
+ memcpy(WFIFOP(fd,36),map3,16);
+ memcpy(WFIFOP(fd,52),map4,16);
+ WFIFOSET(fd,packet_db[0x11c].len);
+ return 0;
+}
+/*==========================================
+ * メモ応答
+ *------------------------------------------
+ */
+int clif_skill_memo(struct map_session_data *sd,int flag)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+
+ WFIFOW(fd,0)=0x11e;
+ WFIFOB(fd,2)=flag;
+ WFIFOSET(fd,packet_db[0x11e].len);
+ return 0;
+}
+int clif_skill_teleportmessage(struct map_session_data *sd,int flag)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x189;
+ WFIFOW(fd,2)=flag;
+ WFIFOSET(fd,packet_db[0x189].len);
+ return 0;
+}
+
+/*==========================================
+ * モンスター情報
+ *------------------------------------------
+ */
+int clif_skill_estimation(struct map_session_data *sd,struct block_list *dst)
+{
+ struct mob_data *md;
+ unsigned char buf[64];
+ int i;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, dst);
+
+ if(dst->type!=BL_MOB )
+ return 0;
+ if((md=(struct mob_data *)dst) == NULL)
+ return 0;
+
+ WBUFW(buf, 0)=0x18c;
+ WBUFW(buf, 2)=mob_get_viewclass(md->class);
+ WBUFW(buf, 4)=mob_db[md->class].lv;
+ WBUFW(buf, 6)=mob_db[md->class].size;
+ WBUFL(buf, 8)=md->hp;
+ WBUFW(buf,12)=battle_get_def2(&md->bl);
+ WBUFW(buf,14)=mob_db[md->class].race;
+ WBUFW(buf,16)=battle_get_mdef2(&md->bl) - (mob_db[md->class].vit>>1);
+ WBUFW(buf,18)=battle_get_elem_type(&md->bl);
+ for(i=0;i<9;i++)
+ WBUFB(buf,20+i)= battle_attr_fix(100,i+1,md->def_ele);
+
+ if(sd->status.party_id>0)
+ clif_send(buf,packet_db[0x18c].len,&sd->bl,PARTY_AREA);
+ else{
+ memcpy(WFIFOP(sd->fd,0),buf,packet_db[0x18c].len);
+ WFIFOSET(sd->fd,packet_db[0x18c].len);
+ }
+ return 0;
+}
+/*==========================================
+ * アイテム合成可能リスト
+ *------------------------------------------
+ */
+int clif_skill_produce_mix_list(struct map_session_data *sd,int trigger)
+{
+ int i,c,view,fd;
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd, 0)=0x18d;
+
+ for(i=0,c=0;i<MAX_SKILL_PRODUCE_DB;i++){
+ if( skill_can_produce_mix(sd,skill_produce_db[i].nameid,trigger) ){
+ if((view = itemdb_viewid(skill_produce_db[i].nameid)) > 0)
+ WFIFOW(fd,c*8+ 4)= view;
+ else
+ WFIFOW(fd,c*8+ 4)= skill_produce_db[i].nameid;
+ WFIFOW(fd,c*8+ 6)= 0x0012;
+ WFIFOL(fd,c*8+ 8)= sd->status.char_id;
+ c++;
+ }
+ }
+ WFIFOW(fd, 2)=c*8+8;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ if(c > 0) sd->state.produce_flag = 1;
+ return 0;
+}
+
+/*==========================================
+ * 状態異常アイコン/メッセージ表示
+ *------------------------------------------
+ */
+int clif_status_change(struct block_list *bl,int type,int flag)
+{
+ unsigned char buf[16];
+
+ nullpo_retr(0, bl);
+
+ WBUFW(buf,0)=0x0196;
+ WBUFW(buf,2)=type;
+ WBUFL(buf,4)=bl->id;
+ WBUFB(buf,8)=flag;
+ clif_send(buf,packet_db[0x196].len,bl,AREA);
+ return 0;
+}
+
+/*==========================================
+ * Send message (modified by [Yor])
+ *------------------------------------------
+ */
+int clif_displaymessage(const int fd, char* mes)
+{
+ //Console [Wizputer]
+ if ( fd == 0 )
+ printf("console: %s\n",mes);
+ else {
+ int len_mes = strlen(mes);
+
+ if (len_mes > 0) { // don't send a void message (it's not displaying on the client chat). @help can send void line.
+ WFIFOW(fd,0) = 0x8e;
+ WFIFOW(fd,2) = 5 + len_mes; // 4 + len + NULL teminate
+ memcpy(WFIFOP(fd,4), mes, len_mes + 1);
+ WFIFOSET(fd, 5 + len_mes);
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 天の声を送信する
+ *------------------------------------------
+ */
+int clif_GMmessage(struct block_list *bl, char* mes, int len, int flag)
+{
+ unsigned char lbuf[255];
+ unsigned char *buf = ((len + 16) >= sizeof(lbuf)) ? malloc(len+16) : lbuf;
+ int lp = (flag&0x10) ? 8 : 4;
+
+ WBUFW(buf,0) = 0x9a;
+ WBUFW(buf,2) = len + lp;
+ WBUFL(buf,4) = 0x65756c62;
+ memcpy(WBUFP(buf,lp), mes, len);
+ flag &= 0x07;
+ clif_send(buf, WBUFW(buf,2), bl,
+ (flag==1) ? ALL_SAMEMAP:
+ (flag==2) ? AREA:
+ (flag==3) ? SELF:
+ ALL_CLIENT);
+ if (buf != lbuf)
+ free(buf);
+ return 0;
+}
+
+/*==========================================
+ * HPSP回復エフェクトを送信する
+ *------------------------------------------
+ */
+int clif_heal(int fd,int type,int val)
+{
+ WFIFOW(fd,0)=0x13d;
+ WFIFOW(fd,2)=type;
+ WFIFOW(fd,4)=val;
+ WFIFOSET(fd,packet_db[0x13d].len);
+
+ return 0;
+}
+
+/*==========================================
+ * 復活する
+ *------------------------------------------
+ */
+int clif_resurrection(struct block_list *bl,int type)
+{
+ unsigned char buf[16];
+
+ nullpo_retr(0, bl);
+
+ if(bl->type==BL_PC) { // disguises [Valaris]
+ struct map_session_data *sd=((struct map_session_data *)bl);
+ if(sd && sd->disguise > 23 && sd->disguise < 4001)
+ clif_spawnpc(sd);
+ }
+
+ WBUFW(buf,0)=0x148;
+ WBUFL(buf,2)=bl->id;
+ WBUFW(buf,6)=type;
+
+ clif_send(buf,packet_db[0x148].len,bl,type==1 ? AREA : AREA_WOS);
+
+ return 0;
+}
+
+/*==========================================
+ * PVP実装?(仮)
+ *------------------------------------------
+ */
+int clif_set0199(int fd,int type)
+{
+ WFIFOW(fd,0)=0x199;
+ WFIFOW(fd,2)=type;
+ WFIFOSET(fd,packet_db[0x199].len);
+
+ return 0;
+}
+
+/*==========================================
+ * PVP実装?(仮)
+ *------------------------------------------
+ */
+int clif_pvpset(struct map_session_data *sd,int pvprank,int pvpnum,int type)
+{
+ nullpo_retr(0, sd);
+
+ if(map[sd->bl.m].flag.nopvp)
+ return 0;
+
+ if(type == 2) {
+ WFIFOW(sd->fd,0) = 0x19a;
+ WFIFOL(sd->fd,2) = sd->bl.id;
+ if(pvprank<=0)
+ pc_calc_pvprank(sd);
+ WFIFOL(sd->fd,6) = pvprank;
+ WFIFOL(sd->fd,10) = pvpnum;
+ WFIFOSET(sd->fd,packet_db[0x19a].len);
+ } else {
+ char buf[32];
+
+ WBUFW(buf,0) = 0x19a;
+ WBUFL(buf,2) = sd->bl.id;
+ if(sd->status.option&0x46)
+ WBUFL(buf,6) = -1;
+ else
+ if(pvprank<=0)
+ pc_calc_pvprank(sd);
+ WBUFL(buf,6) = pvprank;
+ WBUFL(buf,10) = pvpnum;
+ if(!type)
+ clif_send(buf,packet_db[0x19a].len,&sd->bl,AREA);
+ else
+ clif_send(buf,packet_db[0x19a].len,&sd->bl,ALL_SAMEMAP);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_send0199(int map,int type)
+{
+ struct block_list bl;
+ char buf[16];
+
+ bl.m = map;
+ WBUFW(buf,0)=0x199;
+ WBUFW(buf,2)=type;
+ clif_send(buf,packet_db[0x199].len,&bl,ALL_SAMEMAP);
+
+ return 0;
+}
+
+/*==========================================
+ * 精錬エフェクトを送信する
+ *------------------------------------------
+ */
+int clif_refine(int fd,struct map_session_data *sd,int fail,int index,int val)
+{
+ WFIFOW(fd,0)=0x188;
+ WFIFOW(fd,2)=fail;
+ WFIFOW(fd,4)=index+2;
+ WFIFOW(fd,6)=val;
+ WFIFOSET(fd,packet_db[0x188].len);
+
+ return 0;
+}
+
+/*==========================================
+ * Wisp/page is transmitted to the destination player
+ *------------------------------------------
+ */
+int clif_wis_message(int fd, char *nick, char *mes, int mes_len) // R 0097 <len>.w <nick>.24B <message>.?B
+{
+ WFIFOW(fd,0) = 0x97;
+ WFIFOW(fd,2) = mes_len + 24 + 4;
+ memcpy(WFIFOP(fd,4), nick, 24);
+ memcpy(WFIFOP(fd,28), mes, mes_len);
+ WFIFOSET(fd,WFIFOW(fd,2));
+ return 0;
+}
+
+/*==========================================
+ * The transmission result of Wisp/page is transmitted to the source player
+ *------------------------------------------
+ */
+int clif_wis_end(int fd, int flag) // R 0098 <type>.B: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
+{
+ WFIFOW(fd,0) = 0x98;
+ WFIFOW(fd,2) = flag;
+ WFIFOSET(fd,packet_db[0x98].len);
+ return 0;
+}
+
+/*==========================================
+ * キャラID名前引き結果を送信する
+ *------------------------------------------
+ */
+int clif_solved_charname(struct map_session_data *sd,int char_id)
+{
+ char *p= map_charid2nick(char_id);
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ if(p!=NULL){
+ WFIFOW(fd,0)=0x194;
+ WFIFOL(fd,2)=char_id;
+ memcpy(WFIFOP(fd,6), p,24 );
+ WFIFOSET(fd,packet_db[0x194].len);
+ }else{
+ map_reqchariddb(sd,char_id);
+ chrif_searchcharid(char_id);
+ }
+ return 0;
+}
+
+/*==========================================
+ * カードの挿入可能リストを返す
+ *------------------------------------------
+ */
+int clif_use_card(struct map_session_data *sd,int idx)
+{
+ nullpo_retr(0, sd);
+
+ if(sd->inventory_data[idx]) {
+ int i,c;
+ int ep=sd->inventory_data[idx]->equip;
+ int fd=sd->fd;
+ WFIFOW(fd,0)=0x017b;
+
+ for(i=c=0;i<MAX_INVENTORY;i++){
+ int j;
+
+ if(sd->inventory_data[i] == NULL)
+ continue;
+ if(sd->inventory_data[i]->type!=4 && sd->inventory_data[i]->type!=5) // 武器防具じゃない
+ continue;
+ if(sd->status.inventory[i].card[0]==0x00ff) // 製造武器
+ continue;
+ if(sd->status.inventory[i].card[0]==(short)0xff00 || sd->status.inventory[i].card[0]==0x00fe)
+ continue;
+ if(sd->status.inventory[i].identify==0 ) // 未鑑定
+ continue;
+
+ if((sd->inventory_data[i]->equip&ep)==0) // 装備個所が違う
+ continue;
+ if(sd->inventory_data[i]->type==4 && ep==32) // 盾カードと両手武器
+ continue;
+
+ for(j=0;j<sd->inventory_data[i]->slot;j++){
+ if( sd->status.inventory[i].card[j]==0 )
+ break;
+ }
+ if(j==sd->inventory_data[i]->slot) // すでにカードが一杯
+ continue;
+
+ WFIFOW(fd,4+c*2)=i+2;
+ c++;
+ }
+ WFIFOW(fd,2)=4+c*2;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+
+ return 0;
+}
+/*==========================================
+ * カードの挿入終了
+ *------------------------------------------
+ */
+int clif_insert_card(struct map_session_data *sd,int idx_equip,int idx_card,int flag)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x17d;
+ WFIFOW(fd,2)=idx_equip+2;
+ WFIFOW(fd,4)=idx_card+2;
+ WFIFOB(fd,6)=flag;
+ WFIFOSET(fd,packet_db[0x17d].len);
+ return 0;
+}
+
+/*==========================================
+ * 鑑定可能アイテムリスト送信
+ *------------------------------------------
+ */
+int clif_item_identify_list(struct map_session_data *sd)
+{
+ int i,c;
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+
+ WFIFOW(fd,0)=0x177;
+ for(i=c=0;i<MAX_INVENTORY;i++){
+ if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].identify!=1){
+ WFIFOW(fd,c*2+4)=i+2;
+ c++;
+ }
+ }
+ if(c > 0) {
+ WFIFOW(fd,2)=c*2+4;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+ return 0;
+}
+
+/*==========================================
+ * 鑑定結果
+ *------------------------------------------
+ */
+int clif_item_identified(struct map_session_data *sd,int idx,int flag)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd, 0)=0x179;
+ WFIFOW(fd, 2)=idx+2;
+ WFIFOB(fd, 4)=flag;
+ WFIFOSET(fd,packet_db[0x179].len);
+ return 0;
+}
+
+/*==========================================
+ * 修理可能アイテムリスト送信
+ * ※実際のパケットがわからないので動作しません
+ *------------------------------------------
+ */
+int clif_item_repair_list(struct map_session_data *sd)
+{
+ int i,c;
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+
+ WFIFOW(fd,0)=0x0;
+ for(i=c=0;i<MAX_INVENTORY;i++){
+ if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].attribute==1){
+ WFIFOW(fd,c*2+4)=i+2;
+ c++;
+ }
+ }
+ if(c > 0) {
+ WFIFOW(fd,2)=c*2+4;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+ return 0;
+}
+
+/*==========================================
+ * アイテムによる一時的なスキル効果
+ *------------------------------------------
+ */
+int clif_item_skill(struct map_session_data *sd,int skillid,int skilllv,const char *name)
+{
+ int range,fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd, 0)=0x147;
+ WFIFOW(fd, 2)=skillid;
+ WFIFOW(fd, 4)=skill_get_inf(skillid);
+ WFIFOW(fd, 6)=0;
+ WFIFOW(fd, 8)=skilllv;
+ WFIFOW(fd,10)=skill_get_sp(skillid,skilllv);
+ range = skill_get_range(skillid,skilllv);
+ if(range < 0)
+ range = battle_get_range(&sd->bl) - (range + 1);
+ WFIFOW(fd,12)=range;
+ memcpy(WFIFOP(fd,14),name,24);
+ WFIFOB(fd,38)=0;
+ WFIFOSET(fd,packet_db[0x147].len);
+ return 0;
+}
+
+/*==========================================
+ * カートにアイテム追加
+ *------------------------------------------
+ */
+int clif_cart_additem(struct map_session_data *sd,int n,int amount,int fail)
+{
+ int view,j,fd;
+ unsigned char *buf;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ buf=WFIFOP(fd,0);
+ if(n<0 || n>=MAX_CART || sd->status.cart[n].nameid<=0)
+ return 1;
+
+ WBUFW(buf,0)=0x124;
+ WBUFW(buf,2)=n+2;
+ WBUFL(buf,4)=amount;
+ if((view = itemdb_viewid(sd->status.cart[n].nameid)) > 0)
+ WBUFW(buf,8)=view;
+ else
+ WBUFW(buf,8)=sd->status.cart[n].nameid;
+ WBUFB(buf,10)=sd->status.cart[n].identify;
+ WBUFB(buf,11)=sd->status.cart[n].attribute;
+ WBUFB(buf,12)=sd->status.cart[n].refine;
+ if(sd->status.cart[n].card[0]==0x00ff || sd->status.cart[n].card[0]==0x00fe || sd->status.cart[n].card[0]==(short)0xff00) {
+ WBUFW(buf,13)=sd->status.cart[n].card[0];
+ WBUFW(buf,15)=sd->status.cart[n].card[1];
+ WBUFW(buf,17)=sd->status.cart[n].card[2];
+ WBUFW(buf,19)=sd->status.cart[n].card[3];
+ } else {
+ if(sd->status.cart[n].card[0] > 0 && (j=itemdb_viewid(sd->status.cart[n].card[0])) > 0)
+ WBUFW(buf,13)= j;
+ else
+ WBUFW(buf,13)= sd->status.cart[n].card[0];
+ if(sd->status.cart[n].card[1] > 0 && (j=itemdb_viewid(sd->status.cart[n].card[1])) > 0)
+ WBUFW(buf,15)= j;
+ else
+ WBUFW(buf,15)= sd->status.cart[n].card[1];
+ if(sd->status.cart[n].card[2] > 0 && (j=itemdb_viewid(sd->status.cart[n].card[2])) > 0)
+ WBUFW(buf,17)= j;
+ else
+ WBUFW(buf,17)= sd->status.cart[n].card[2];
+ if(sd->status.cart[n].card[3] > 0 && (j=itemdb_viewid(sd->status.cart[n].card[3])) > 0)
+ WBUFW(buf,19)= j;
+ else
+ WBUFW(buf,19)= sd->status.cart[n].card[3];
+ }
+ WFIFOSET(fd,packet_db[0x124].len);
+ return 0;
+}
+
+/*==========================================
+ * カートからアイテム削除
+ *------------------------------------------
+ */
+int clif_cart_delitem(struct map_session_data *sd,int n,int amount)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+
+ WFIFOW(fd,0)=0x125;
+ WFIFOW(fd,2)=n+2;
+ WFIFOL(fd,4)=amount;
+
+ WFIFOSET(fd,packet_db[0x125].len);
+
+ return 0;
+}
+
+/*==========================================
+ * カートのアイテムリスト
+ *------------------------------------------
+ */
+int clif_cart_itemlist(struct map_session_data *sd)
+{
+ struct item_data *id;
+ int i,n,fd;
+ unsigned char *buf;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ buf = WFIFOP(fd,0);
+#if PACKETVER < 5
+ WBUFW(buf,0)=0x123;
+ for(i=0,n=0;i<MAX_CART;i++){
+ if(sd->status.cart[i].nameid<=0)
+ continue;
+ id = itemdb_search(sd->status.cart[i].nameid);
+ if(itemdb_isequip2(id))
+ continue;
+ WBUFW(buf,n*10+4)=i+2;
+ if(id->view_id > 0)
+ WBUFW(buf,n*10+6)=id->view_id;
+ else
+ WBUFW(buf,n*10+6)=sd->status.cart[i].nameid;
+ WBUFB(buf,n*10+8)=id->type;
+ WBUFB(buf,n*10+9)=sd->status.cart[i].identify;
+ WBUFW(buf,n*10+10)=sd->status.cart[i].amount;
+ WBUFW(buf,n*10+12)=0;
+ n++;
+ }
+ if(n){
+ WBUFW(buf,2)=4+n*10;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+#else
+ WBUFW(buf,0)=0x1ef;
+ for(i=0,n=0;i<MAX_CART;i++){
+ if(sd->status.cart[i].nameid<=0)
+ continue;
+ id = itemdb_search(sd->status.cart[i].nameid);
+ if(itemdb_isequip2(id))
+ continue;
+ WBUFW(buf,n*18+4)=i+2;
+ if(id->view_id > 0)
+ WBUFW(buf,n*18+6)=id->view_id;
+ else
+ WBUFW(buf,n*18+6)=sd->status.cart[i].nameid;
+ WBUFB(buf,n*18+8)=id->type;
+ WBUFB(buf,n*18+9)=sd->status.cart[i].identify;
+ WBUFW(buf,n*18+10)=sd->status.cart[i].amount;
+ WBUFW(buf,n*18+12)=0;
+ WBUFW(buf,n*18+14)=sd->status.cart[i].card[0];
+ WBUFW(buf,n*18+16)=sd->status.cart[i].card[1];
+ WBUFW(buf,n*18+18)=sd->status.cart[i].card[2];
+ WBUFW(buf,n*18+20)=sd->status.cart[i].card[3];
+ n++;
+ }
+ if(n){
+ WBUFW(buf,2)=4+n*18;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+#endif
+ return 0;
+}
+
+/*==========================================
+ * カートの装備品リスト
+ *------------------------------------------
+ */
+int clif_cart_equiplist(struct map_session_data *sd)
+{
+ struct item_data *id;
+ int i,j,n,fd;
+ unsigned char *buf;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ buf = WFIFOP(fd,0);
+
+ WBUFW(buf,0)=0x122;
+ for(i=0,n=0;i<MAX_INVENTORY;i++){
+ if(sd->status.cart[i].nameid<=0)
+ continue;
+ id = itemdb_search(sd->status.cart[i].nameid);
+ if(!itemdb_isequip2(id))
+ continue;
+ WBUFW(buf,n*20+4)=i+2;
+ if(id->view_id > 0)
+ WBUFW(buf,n*20+6)=id->view_id;
+ else
+ WBUFW(buf,n*20+6)=sd->status.cart[i].nameid;
+ WBUFB(buf,n*20+8)=id->type;
+ WBUFB(buf,n*20+9)=sd->status.cart[i].identify;
+ WBUFW(buf,n*20+10)=id->equip;
+ WBUFW(buf,n*20+12)=sd->status.cart[i].equip;
+ WBUFB(buf,n*20+14)=sd->status.cart[i].attribute;
+ WBUFB(buf,n*20+15)=sd->status.cart[i].refine;
+ if(sd->status.cart[i].card[0]==0x00ff || sd->status.cart[i].card[0]==0x00fe || sd->status.cart[i].card[0]==(short)0xff00) {
+ WBUFW(buf,n*20+16)=sd->status.cart[i].card[0];
+ WBUFW(buf,n*20+18)=sd->status.cart[i].card[1];
+ WBUFW(buf,n*20+20)=sd->status.cart[i].card[2];
+ WBUFW(buf,n*20+22)=sd->status.cart[i].card[3];
+ } else {
+ if(sd->status.cart[i].card[0] > 0 && (j=itemdb_viewid(sd->status.cart[i].card[0])) > 0)
+ WBUFW(buf,n*20+16)= j;
+ else
+ WBUFW(buf,n*20+16)= sd->status.cart[i].card[0];
+ if(sd->status.cart[i].card[1] > 0 && (j=itemdb_viewid(sd->status.cart[i].card[1])) > 0)
+ WBUFW(buf,n*20+18)= j;
+ else
+ WBUFW(buf,n*20+18)= sd->status.cart[i].card[1];
+ if(sd->status.cart[i].card[2] > 0 && (j=itemdb_viewid(sd->status.cart[i].card[2])) > 0)
+ WBUFW(buf,n*20+20)= j;
+ else
+ WBUFW(buf,n*20+20)= sd->status.cart[i].card[2];
+ if(sd->status.cart[i].card[3] > 0 && (j=itemdb_viewid(sd->status.cart[i].card[3])) > 0)
+ WBUFW(buf,n*20+22)= j;
+ else
+ WBUFW(buf,n*20+22)= sd->status.cart[i].card[3];
+ }
+ n++;
+ }
+ if(n){
+ WBUFW(buf,2)=4+n*20;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+ return 0;
+}
+
+/*==========================================
+ * 露店開設
+ *------------------------------------------
+ */
+int clif_openvendingreq(struct map_session_data *sd,int num)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x12d;
+ WFIFOW(fd,2)=num;
+ WFIFOSET(fd,packet_db[0x12d].len);
+
+ return 0;
+}
+
+/*==========================================
+ * 露店看板表示
+ *------------------------------------------
+ */
+int clif_showvendingboard(struct block_list* bl,char *message,int fd)
+{
+ unsigned char buf[128];
+
+ nullpo_retr(0, bl);
+
+ WBUFW(buf,0)=0x131;
+ WBUFL(buf,2)=bl->id;
+ strncpy(WBUFP(buf,6),message,80);
+ if(fd){
+ memcpy(WFIFOP(fd,0),buf,packet_db[0x131].len);
+ WFIFOSET(fd,packet_db[0x131].len);
+ }else{
+ clif_send(buf,packet_db[0x131].len,bl,AREA_WOS);
+ }
+ return 0;
+}
+
+/*==========================================
+ * 露店看板消去
+ *------------------------------------------
+ */
+int clif_closevendingboard(struct block_list* bl,int fd)
+{
+ unsigned char buf[16];
+
+ nullpo_retr(0, bl);
+
+ WBUFW(buf,0)=0x132;
+ WBUFL(buf,2)=bl->id;
+ if(fd){
+ memcpy(WFIFOP(fd,0),buf,packet_db[0x132].len);
+ WFIFOSET(fd,packet_db[0x132].len);
+ }else{
+ clif_send(buf,packet_db[0x132].len,bl,AREA_WOS);
+ }
+
+ return 0;
+}
+/*==========================================
+ * 露店アイテムリスト
+ *------------------------------------------
+ */
+int clif_vendinglist(struct map_session_data *sd,int id,struct vending *vending)
+{
+ struct item_data *data;
+ int i,j,n,index,fd;
+ struct map_session_data *vsd;
+ unsigned char *buf;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, vending);
+ nullpo_retr(0, vsd=map_id2sd(id));
+
+ fd=sd->fd;
+ buf = WFIFOP(fd,0);
+ WBUFW(buf,0)=0x133;
+ WBUFL(buf,4)=id;
+ for(i=0,n=0;i<vsd->vend_num;i++){
+ if(vending[i].amount<=0)
+ continue;
+ WBUFL(buf,8+n*22)=vending[i].value;
+ WBUFW(buf,12+n*22)=vending[i].amount;
+ WBUFW(buf,14+n*22)=(index=vending[i].index)+2;
+ if(vsd->status.cart[index].nameid <= 0 || vsd->status.cart[index].amount <= 0)
+ continue;
+ data = itemdb_search(vsd->status.cart[index].nameid);
+ WBUFB(buf,16+n*22)=data->type;
+ if(data->view_id > 0)
+ WBUFW(buf,17+n*22)=data->view_id;
+ else
+ WBUFW(buf,17+n*22)=vsd->status.cart[index].nameid;
+ WBUFB(buf,19+n*22)=vsd->status.cart[index].identify;
+ WBUFB(buf,20+n*22)=vsd->status.cart[index].attribute;
+ WBUFB(buf,21+n*22)=vsd->status.cart[index].refine;
+ if(vsd->status.cart[index].card[0]==0x00ff || vsd->status.cart[index].card[0]==0x00fe || vsd->status.cart[index].card[0]==(short)0xff00) {
+ WBUFW(buf,22+n*22)=vsd->status.cart[index].card[0];
+ WBUFW(buf,24+n*22)=vsd->status.cart[index].card[1];
+ WBUFW(buf,26+n*22)=vsd->status.cart[index].card[2];
+ WBUFW(buf,28+n*22)=vsd->status.cart[index].card[3];
+ } else {
+ if(vsd->status.cart[index].card[0] > 0 && (j=itemdb_viewid(vsd->status.cart[index].card[0])) > 0)
+ WBUFW(buf,22+n*22)= j;
+ else
+ WBUFW(buf,22+n*22)= vsd->status.cart[index].card[0];
+ if(vsd->status.cart[index].card[1] > 0 && (j=itemdb_viewid(vsd->status.cart[index].card[1])) > 0)
+ WBUFW(buf,24+n*22)= j;
+ else
+ WBUFW(buf,24+n*22)= vsd->status.cart[index].card[1];
+ if(vsd->status.cart[index].card[2] > 0 && (j=itemdb_viewid(vsd->status.cart[index].card[2])) > 0)
+ WBUFW(buf,26+n*22)= j;
+ else
+ WBUFW(buf,26+n*22)= vsd->status.cart[index].card[2];
+ if(vsd->status.cart[index].card[3] > 0 && (j=itemdb_viewid(vsd->status.cart[index].card[3])) > 0)
+ WBUFW(buf,28+n*22)= j;
+ else
+ WBUFW(buf,28+n*22)= vsd->status.cart[index].card[3];
+ }
+ n++;
+ }
+ if(n > 0){
+ WBUFW(buf,2)=8+n*22;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 露店アイテム購入失敗
+ *------------------------------------------
+*/
+int clif_buyvending(struct map_session_data *sd,int index,int amount,int fail)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x135;
+ WFIFOW(fd,2)=index+2;
+ WFIFOW(fd,4)=amount;
+ WFIFOB(fd,6)=fail;
+ WFIFOSET(fd,packet_db[0x135].len);
+
+ return 0;
+}
+
+/*==========================================
+ * 露店開設成功
+ *------------------------------------------
+*/
+int clif_openvending(struct map_session_data *sd,int id,struct vending *vending)
+{
+ struct item_data *data;
+ int i,j,n,index,fd;
+ unsigned char *buf;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ buf = WFIFOP(fd,0);
+
+ WBUFW(buf,0)=0x136;
+ WBUFL(buf,4)=id;
+ for(i=0,n=0;i<sd->vend_num;i++){
+ if (sd->vend_num > 2+pc_checkskill(sd,MC_VENDING)) return 0;
+ WBUFL(buf,8+n*22)=vending[i].value;
+ WBUFW(buf,12+n*22)=(index=vending[i].index)+2;
+ WBUFW(buf,14+n*22)=vending[i].amount;
+ if(sd->status.cart[index].nameid <= 0 || sd->status.cart[index].amount <= 0 || sd->status.cart[index].identify==0 ||
+ sd->status.cart[index].attribute==1) // Prevent unidentified and broken items from being sold [Valaris]
+ continue;
+ data = itemdb_search(sd->status.cart[index].nameid);
+ WBUFB(buf,16+n*22)=data->type;
+ if(data->view_id > 0)
+ WBUFW(buf,17+n*22)=data->view_id;
+ else
+ WBUFW(buf,17+n*22)=sd->status.cart[index].nameid;
+ WBUFB(buf,19+n*22)=sd->status.cart[index].identify;
+ WBUFB(buf,20+n*22)=sd->status.cart[index].attribute;
+ WBUFB(buf,21+n*22)=sd->status.cart[index].refine;
+ if(sd->status.cart[index].card[0]==0x00ff || sd->status.cart[index].card[0]==0x00fe || sd->status.cart[index].card[0]==(short)0xff00) {
+ WBUFW(buf,22+n*22)=sd->status.cart[index].card[0];
+ WBUFW(buf,24+n*22)=sd->status.cart[index].card[1];
+ WBUFW(buf,26+n*22)=sd->status.cart[index].card[2];
+ WBUFW(buf,28+n*22)=sd->status.cart[index].card[3];
+ } else {
+ if(sd->status.cart[index].card[0] > 0 && (j=itemdb_viewid(sd->status.cart[index].card[0])) > 0)
+ WBUFW(buf,22+n*22)= j;
+ else
+ WBUFW(buf,22+n*22)= sd->status.cart[index].card[0];
+ if(sd->status.cart[index].card[1] > 0 && (j=itemdb_viewid(sd->status.cart[index].card[1])) > 0)
+ WBUFW(buf,24+n*22)= j;
+ else
+ WBUFW(buf,24+n*22)= sd->status.cart[index].card[1];
+ if(sd->status.cart[index].card[2] > 0 && (j=itemdb_viewid(sd->status.cart[index].card[2])) > 0)
+ WBUFW(buf,26+n*22)= j;
+ else
+ WBUFW(buf,26+n*22)= sd->status.cart[index].card[2];
+ if(sd->status.cart[index].card[3] > 0 && (j=itemdb_viewid(sd->status.cart[index].card[3])) > 0)
+ WBUFW(buf,28+n*22)= j;
+ else
+ WBUFW(buf,28+n*22)= sd->status.cart[index].card[3];
+ }
+ n++;
+ }
+ if(n > 0){
+ WBUFW(buf,2)=8+n*22;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+
+ return n;
+}
+
+/*==========================================
+ * 露店アイテム販売報告
+ *------------------------------------------
+*/
+int clif_vendingreport(struct map_session_data *sd,int index,int amount)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x137;
+ WFIFOW(fd,2)=index+2;
+ WFIFOW(fd,4)=amount;
+ WFIFOSET(fd,packet_db[0x137].len);
+
+ return 0;
+}
+
+/*==========================================
+ * パーティ作成完了
+ *------------------------------------------
+ */
+int clif_party_created(struct map_session_data *sd,int flag)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xfa;
+ WFIFOB(fd,2)=flag;
+ WFIFOSET(fd,packet_db[0xfa].len);
+ return 0;
+}
+/*==========================================
+ * パーティ情報送信
+ *------------------------------------------
+ */
+int clif_party_info(struct party *p,int fd)
+{
+ unsigned char buf[1024];
+ int i,c;
+ struct map_session_data *sd=NULL;
+
+ nullpo_retr(0, p);
+
+ WBUFW(buf,0)=0xfb;
+ memcpy(WBUFP(buf,4),p->name,24);
+ for(i=c=0;i<MAX_PARTY;i++){
+ struct party_member *m=&p->member[i];
+ if(m->account_id>0){
+ if(sd==NULL) sd=m->sd;
+ WBUFL(buf,28+c*46)=m->account_id;
+ memcpy(WBUFP(buf,28+c*46+ 4),m->name,24);
+ memcpy(WBUFP(buf,28+c*46+28),m->map,16);
+ WBUFB(buf,28+c*46+44)=(m->leader)?0:1;
+ WBUFB(buf,28+c*46+45)=(m->online)?0:1;
+ c++;
+ }
+ }
+ WBUFW(buf,2)=28+c*46;
+ if(fd>=0){ // fdが設定されてるならそれに送る
+ memcpy(WFIFOP(fd,0),buf,WBUFW(buf,2));
+ WFIFOSET(fd,WFIFOW(fd,2));
+ return 9;
+ }
+ if(sd!=NULL)
+ clif_send(buf,WBUFW(buf,2),&sd->bl,PARTY);
+ return 0;
+}
+/*==========================================
+ * パーティ勧誘
+ *------------------------------------------
+ */
+int clif_party_invite(struct map_session_data *sd,struct map_session_data *tsd)
+{
+ int fd;
+ struct party *p;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, tsd);
+
+ fd=tsd->fd;
+
+ if( (p=party_search(sd->status.party_id))==NULL )
+ return 0;
+
+ WFIFOW(fd,0)=0xfe;
+ WFIFOL(fd,2)=sd->status.account_id;
+ memcpy(WFIFOP(fd,6),p->name,24);
+ WFIFOSET(fd,packet_db[0xfe].len);
+ return 0;
+}
+
+/*==========================================
+ * パーティ勧誘結果
+ *------------------------------------------
+ */
+int clif_party_inviteack(struct map_session_data *sd,char *nick,int flag)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xfd;
+ memcpy(WFIFOP(fd,2),nick,24);
+ WFIFOB(fd,26)=flag;
+ WFIFOSET(fd,packet_db[0xfd].len);
+ return 0;
+}
+
+/*==========================================
+ * パーティ設定送信
+ * flag & 0x001=exp変更ミス
+ * 0x010=item変更ミス
+ * 0x100=一人にのみ送信
+ *------------------------------------------
+ */
+int clif_party_option(struct party *p,struct map_session_data *sd,int flag)
+{
+ unsigned char buf[16];
+
+ nullpo_retr(0, p);
+
+// if(battle_config.etc_log)
+// printf("clif_party_option: %d %d %d\n",p->exp,p->item,flag);
+ if(sd==NULL && flag==0){
+ int i;
+ for(i=0;i<MAX_PARTY;i++)
+ if((sd=map_id2sd(p->member[i].account_id))!=NULL)
+ break;
+ }
+ if(sd==NULL)
+ return 0;
+ WBUFW(buf,0)=0x101;
+ WBUFW(buf,2)=((flag&0x01)?2:p->exp);
+ WBUFW(buf,4)=((flag&0x10)?2:p->item);
+ if(flag==0)
+ clif_send(buf,packet_db[0x101].len,&sd->bl,PARTY);
+ else {
+ memcpy(WFIFOP(sd->fd,0),buf,packet_db[0x101].len);
+ WFIFOSET(sd->fd,packet_db[0x101].len);
+ }
+ return 0;
+}
+/*==========================================
+ * パーティ脱退(脱退前に呼ぶこと)
+ *------------------------------------------
+ */
+int clif_party_leaved(struct party *p,struct map_session_data *sd,int account_id,char *name,int flag)
+{
+ unsigned char buf[64];
+ int i;
+
+ nullpo_retr(0, p);
+
+ WBUFW(buf,0)=0x105;
+ WBUFL(buf,2)=account_id;
+ memcpy(WBUFP(buf,6),name,24);
+ WBUFB(buf,30)=flag&0x0f;
+
+ if((flag&0xf0)==0){
+ if(sd==NULL)
+ for(i=0;i<MAX_PARTY;i++)
+ if((sd=p->member[i].sd)!=NULL)
+ break;
+ if (sd!=NULL)
+ clif_send(buf,packet_db[0x105].len,&sd->bl,PARTY);
+ } else if (sd!=NULL) {
+ memcpy(WFIFOP(sd->fd,0),buf,packet_db[0x105].len);
+ WFIFOSET(sd->fd,packet_db[0x105].len);
+ }
+ return 0;
+}
+/*==========================================
+ * パーティメッセージ送信
+ *------------------------------------------
+ */
+int clif_party_message(struct party *p,int account_id,char *mes,int len)
+{
+ struct map_session_data *sd;
+ int i;
+
+ nullpo_retr(0, p);
+
+ for(i=0;i<MAX_PARTY;i++){
+ if((sd=p->member[i].sd)!=NULL)
+ break;
+ }
+ if(sd!=NULL){
+ unsigned char buf[1024];
+ WBUFW(buf,0)=0x109;
+ WBUFW(buf,2)=len+8;
+ WBUFL(buf,4)=account_id;
+ memcpy(WBUFP(buf,8),mes,len);
+ clif_send(buf,len+8,&sd->bl,PARTY);
+ }
+ return 0;
+}
+/*==========================================
+ * パーティ座標通知
+ *------------------------------------------
+ */
+int clif_party_xy(struct party *p,struct map_session_data *sd)
+{
+ unsigned char buf[16];
+
+ nullpo_retr(0, sd);
+
+ WBUFW(buf,0)=0x107;
+ WBUFL(buf,2)=sd->status.account_id;
+ WBUFW(buf,6)=sd->bl.x;
+ WBUFW(buf,8)=sd->bl.y;
+ clif_send(buf,packet_db[0x107].len,&sd->bl,PARTY_SAMEMAP_WOS);
+// if(battle_config.etc_log)
+// printf("clif_party_xy %d\n",sd->status.account_id);
+ return 0;
+}
+/*==========================================
+ * パーティHP通知
+ *------------------------------------------
+ */
+int clif_party_hp(struct party *p,struct map_session_data *sd)
+{
+ unsigned char buf[16];
+
+ nullpo_retr(0, sd);
+
+ WBUFW(buf,0)=0x106;
+ WBUFL(buf,2)=sd->status.account_id;
+ WBUFW(buf,6)=(sd->status.hp > 0x7fff)? 0x7fff:sd->status.hp;
+ WBUFW(buf,8)=(sd->status.max_hp > 0x7fff)? 0x7fff:sd->status.max_hp;
+ clif_send(buf,packet_db[0x106].len,&sd->bl,PARTY_AREA_WOS);
+// if(battle_config.etc_log)
+// printf("clif_party_hp %d\n",sd->status.account_id);
+ return 0;
+}
+/*==========================================
+ * パーティ場所移動(未使用)
+ *------------------------------------------
+ */
+int clif_party_move(struct party *p,struct map_session_data *sd,int online)
+{
+ unsigned char buf[128];
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, p);
+
+ WBUFW(buf, 0)=0x104;
+ WBUFL(buf, 2)=sd->status.account_id;
+ WBUFL(buf, 6)=0;
+ WBUFW(buf,10)=sd->bl.x;
+ WBUFW(buf,12)=sd->bl.y;
+ WBUFB(buf,14)=!online;
+ memcpy(WBUFP(buf,15),p->name,24);
+ memcpy(WBUFP(buf,39),sd->status.name,24);
+ memcpy(WBUFP(buf,63),map[sd->bl.m].name,16);
+ clif_send(buf,packet_db[0x104].len,&sd->bl,PARTY);
+ return 0;
+}
+/*==========================================
+ * 攻撃するために移動が必要
+ *------------------------------------------
+ */
+int clif_movetoattack(struct map_session_data *sd,struct block_list *bl)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, bl);
+
+ fd=sd->fd;
+ WFIFOW(fd, 0)=0x139;
+ WFIFOL(fd, 2)=bl->id;
+ WFIFOW(fd, 6)=bl->x;
+ WFIFOW(fd, 8)=bl->y;
+ WFIFOW(fd,10)=sd->bl.x;
+ WFIFOW(fd,12)=sd->bl.y;
+ WFIFOW(fd,14)=sd->attackrange;
+ WFIFOSET(fd,packet_db[0x139].len);
+ return 0;
+}
+/*==========================================
+ * 製造エフェクト
+ *------------------------------------------
+ */
+int clif_produceeffect(struct map_session_data *sd,int flag,int nameid)
+{
+ int view,fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ // 名前の登録と送信を先にしておく
+ if( map_charid2nick(sd->status.char_id)==NULL )
+ map_addchariddb(sd->status.char_id,sd->status.name);
+ clif_solved_charname(sd,sd->status.char_id);
+
+ WFIFOW(fd, 0)=0x18f;
+ WFIFOW(fd, 2)=flag;
+ if((view = itemdb_viewid(nameid)) > 0)
+ WFIFOW(fd, 4)=view;
+ else
+ WFIFOW(fd, 4)=nameid;
+ WFIFOSET(fd,packet_db[0x18f].len);
+ return 0;
+}
+
+// pet
+int clif_catch_process(struct map_session_data *sd)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x19e;
+ WFIFOSET(fd,packet_db[0x19e].len);
+
+ return 0;
+}
+
+int clif_pet_rulet(struct map_session_data *sd,int data)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x1a0;
+ WFIFOB(fd,2)=data;
+ WFIFOSET(fd,packet_db[0x1a0].len);
+
+ return 0;
+}
+
+/*==========================================
+ * pet卵リスト作成
+ *------------------------------------------
+ */
+int clif_sendegg(struct map_session_data *sd)
+{
+ //R 01a6 <len>.w <index>.w*
+ int i,n=0,fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x1a6;
+ if(sd->status.pet_id <= 0) {
+ for(i=0,n=0;i<MAX_INVENTORY;i++){
+ if(sd->status.inventory[i].nameid<=0 || sd->inventory_data[i] == NULL ||
+ sd->inventory_data[i]->type!=7 ||
+ sd->status.inventory[i].amount<=0)
+ continue;
+ WFIFOW(fd,n*2+4)=i+2;
+ n++;
+ }
+ }
+ WFIFOW(fd,2)=4+n*2;
+ WFIFOSET(fd,WFIFOW(fd,2));
+
+ return 0;
+}
+
+int clif_send_petdata(struct map_session_data *sd,int type,int param)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x1a4;
+ WFIFOB(fd,2)=type;
+ WFIFOL(fd,3)=sd->pd->bl.id;
+ WFIFOL(fd,7)=param;
+ WFIFOSET(fd,packet_db[0x1a4].len);
+
+ return 0;
+}
+
+int clif_send_petstatus(struct map_session_data *sd)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x1a2;
+ memcpy(WFIFOP(fd,2),sd->pet.name,24);
+ WFIFOB(fd,26)=(battle_config.pet_rename == 1)? 0:sd->pet.rename_flag;
+ WFIFOW(fd,27)=sd->pet.level;
+ WFIFOW(fd,29)=sd->pet.hungry;
+ WFIFOW(fd,31)=sd->pet.intimate;
+ WFIFOW(fd,33)=sd->pet.equip;
+ WFIFOSET(fd,packet_db[0x1a2].len);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_pet_emotion(struct pet_data *pd,int param)
+{
+ unsigned char buf[16];
+ struct map_session_data *sd;
+
+ nullpo_retr(0, pd);
+ nullpo_retr(0, sd = pd->msd);
+
+ memset(buf,0,packet_db[0x1aa].len);
+
+ WBUFW(buf,0)=0x1aa;
+ WBUFL(buf,2)=pd->bl.id;
+ if(param >= 100 && sd->petDB->talk_convert_class) {
+ if(sd->petDB->talk_convert_class < 0)
+ return 0;
+ else if(sd->petDB->talk_convert_class > 0) {
+ param -= (pd->class - 100)*100;
+ param += (sd->petDB->talk_convert_class - 100)*100;
+ }
+ }
+ WBUFL(buf,6)=param;
+
+ clif_send(buf,packet_db[0x1aa].len,&pd->bl,AREA);
+
+ return 0;
+}
+
+int clif_pet_performance(struct block_list *bl,int param)
+{
+ unsigned char buf[16];
+
+ nullpo_retr(0, bl);
+
+ memset(buf,0,packet_db[0x1a4].len);
+
+ WBUFW(buf,0)=0x1a4;
+ WBUFB(buf,2)=4;
+ WBUFL(buf,3)=bl->id;
+ WBUFL(buf,7)=param;
+
+ clif_send(buf,packet_db[0x1a4].len,bl,AREA);
+
+ return 0;
+}
+
+int clif_pet_equip(struct pet_data *pd,int nameid)
+{
+ unsigned char buf[16];
+ int view;
+
+ nullpo_retr(0, pd);
+
+ memset(buf,0,packet_db[0x1a4].len);
+
+ WBUFW(buf,0)=0x1a4;
+ WBUFB(buf,2)=3;
+ WBUFL(buf,3)=pd->bl.id;
+ if((view = itemdb_viewid(nameid)) > 0)
+ WBUFL(buf,7)=view;
+ else
+ WBUFL(buf,7)=nameid;
+
+ clif_send(buf,packet_db[0x1a4].len,&pd->bl,AREA);
+
+ return 0;
+}
+
+int clif_pet_food(struct map_session_data *sd,int foodid,int fail)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x1a3;
+ WFIFOB(fd,2)=fail;
+ WFIFOW(fd,3)=foodid;
+ WFIFOSET(fd,packet_db[0x1a3].len);
+
+ return 0;
+}
+
+/*==========================================
+ * オートスペル リスト送信
+ *------------------------------------------
+ */
+int clif_autospell(struct map_session_data *sd,int skilllv)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd, 0)=0x1cd;
+
+ if(skilllv>0 && pc_checkskill(sd,MG_NAPALMBEAT)>0)
+ WFIFOL(fd,2)= MG_NAPALMBEAT;
+ else
+ WFIFOL(fd,2)= 0x00000000;
+ if(skilllv>1 && pc_checkskill(sd,MG_COLDBOLT)>0)
+ WFIFOL(fd,6)= MG_COLDBOLT;
+ else
+ WFIFOL(fd,6)= 0x00000000;
+ if(skilllv>1 && pc_checkskill(sd,MG_FIREBOLT)>0)
+ WFIFOL(fd,10)= MG_FIREBOLT;
+ else
+ WFIFOL(fd,10)= 0x00000000;
+ if(skilllv>1 && pc_checkskill(sd,MG_LIGHTNINGBOLT)>0)
+ WFIFOL(fd,14)= MG_LIGHTNINGBOLT;
+ else
+ WFIFOL(fd,14)= 0x00000000;
+ if(skilllv>4 && pc_checkskill(sd,MG_SOULSTRIKE)>0)
+ WFIFOL(fd,18)= MG_SOULSTRIKE;
+ else
+ WFIFOL(fd,18)= 0x00000000;
+ if(skilllv>7 && pc_checkskill(sd,MG_FIREBALL)>0)
+ WFIFOL(fd,22)= MG_FIREBALL;
+ else
+ WFIFOL(fd,22)= 0x00000000;
+ if(skilllv>9 && pc_checkskill(sd,MG_FROSTDIVER)>0)
+ WFIFOL(fd,26)= MG_FROSTDIVER;
+ else
+ WFIFOL(fd,26)= 0x00000000;
+
+ WFIFOSET(fd,packet_db[0x1cd].len);
+ return 0;
+}
+
+/*==========================================
+ * ディボーションの青い糸
+ *------------------------------------------
+ */
+int clif_devotion(struct map_session_data *sd,int target)
+{
+ unsigned char buf[56];
+ int n;
+
+ nullpo_retr(0, sd);
+
+ WBUFW(buf,0)=0x1cf;
+ WBUFL(buf,2)=sd->bl.id;
+// WBUFL(buf,6)=target;
+ for(n=0;n<5;n++)
+ WBUFL(buf,6+4*n)=sd->dev.val2[n];
+// WBUFL(buf,10+4*n)=0;
+ WBUFB(buf,26)=8;
+ WBUFB(buf,27)=0;
+
+ clif_send(buf,packet_db[0x1cf].len,&sd->bl,AREA);
+ return 0;
+}
+
+/*==========================================
+ * 氣球
+ *------------------------------------------
+ */
+int clif_spiritball(struct map_session_data *sd)
+{
+ unsigned char buf[16];
+
+ nullpo_retr(0, sd);
+
+ WBUFW(buf,0)=0x1d0;
+ WBUFL(buf,2)=sd->bl.id;
+ WBUFW(buf,6)=sd->spiritball;
+ clif_send(buf,packet_db[0x1d0].len,&sd->bl,AREA);
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_combo_delay(struct block_list *bl,int wait)
+{
+ unsigned char buf[32];
+
+ nullpo_retr(0, bl);
+
+ WBUFW(buf,0)=0x1d2;
+ WBUFL(buf,2)=bl->id;
+ WBUFL(buf,6)=wait;
+ clif_send(buf,packet_db[0x1d2].len,bl,AREA);
+
+ return 0;
+}
+/*==========================================
+ *白刃取り
+ *------------------------------------------
+ */
+int clif_bladestop(struct block_list *src,struct block_list *dst,
+ int bool)
+{
+ unsigned char buf[32];
+
+ nullpo_retr(0, src);
+ nullpo_retr(0, dst);
+
+ WBUFW(buf,0)=0x1d1;
+ WBUFL(buf,2)=src->id;
+ WBUFL(buf,6)=dst->id;
+ WBUFL(buf,10)=bool;
+
+ clif_send(buf,packet_db[0x1d1].len,src,AREA);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_changemapcell(int m,int x,int y,int cell_type,int type)
+{
+ struct block_list bl;
+ char buf[32];
+
+ bl.m = m;
+ bl.x = x;
+ bl.y = y;
+ WBUFW(buf,0) = 0x192;
+ WBUFW(buf,2) = x;
+ WBUFW(buf,4) = y;
+ WBUFW(buf,6) = cell_type;
+ memcpy(WBUFP(buf,8),map[m].name,16);
+ if(!type)
+ clif_send(buf,packet_db[0x192].len,&bl,AREA);
+ else
+ clif_send(buf,packet_db[0x192].len,&bl,ALL_SAMEMAP);
+
+ return 0;
+}
+
+/*==========================================
+ * MVPエフェクト
+ *------------------------------------------
+ */
+int clif_mvp_effect(struct map_session_data *sd)
+{
+ unsigned char buf[16];
+
+ nullpo_retr(0, sd);
+
+ WBUFW(buf,0)=0x10c;
+ WBUFL(buf,2)=sd->bl.id;
+ clif_send(buf,packet_db[0x10c].len,&sd->bl,AREA);
+ return 0;
+}
+/*==========================================
+ * MVPアイテム所得
+ *------------------------------------------
+ */
+int clif_mvp_item(struct map_session_data *sd,int nameid)
+{
+ int view,fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x10a;
+ if((view = itemdb_viewid(nameid)) > 0)
+ WFIFOW(fd,2)=view;
+ else
+ WFIFOW(fd,2)=nameid;
+ WFIFOSET(fd,packet_db[0x10a].len);
+ return 0;
+}
+/*==========================================
+ * MVP経験値所得
+ *------------------------------------------
+ */
+int clif_mvp_exp(struct map_session_data *sd,int exp)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x10b;
+ WFIFOL(fd,2)=exp;
+ WFIFOSET(fd,packet_db[0x10b].len);
+ return 0;
+}
+
+/*==========================================
+ * ギルド作成可否通知
+ *------------------------------------------
+ */
+int clif_guild_created(struct map_session_data *sd,int flag)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x167;
+ WFIFOB(fd,2)=flag;
+ WFIFOSET(fd,packet_db[0x167].len);
+ return 0;
+}
+/*==========================================
+ * ギルド所属通知
+ *------------------------------------------
+ */
+int clif_guild_belonginfo(struct map_session_data *sd,struct guild *g)
+{
+ int ps,fd;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, g);
+
+ fd=sd->fd;
+ ps=guild_getposition(sd,g);
+
+ memset(WFIFOP(fd,0),0,packet_db[0x16c].len);
+ WFIFOW(fd,0)=0x16c;
+ WFIFOL(fd,2)=g->guild_id;
+ WFIFOL(fd,6)=g->emblem_id;
+ WFIFOL(fd,10)=g->position[ps].mode;
+ memcpy(WFIFOP(fd,19),g->name,24);
+ WFIFOSET(fd,packet_db[0x16c].len);
+ return 0;
+}
+/*==========================================
+ * ギルドメンバログイン通知
+ *------------------------------------------
+ */
+int clif_guild_memberlogin_notice(struct guild *g,int idx,int flag)
+{
+ unsigned char buf[64];
+
+ nullpo_retr(0, g);
+
+ WBUFW(buf, 0)=0x16d;
+ WBUFL(buf, 2)=g->member[idx].account_id;
+ WBUFL(buf, 6)=g->member[idx].char_id;
+ WBUFL(buf,10)=flag;
+ if(g->member[idx].sd==NULL){
+ struct map_session_data *sd=guild_getavailablesd(g);
+ if(sd!=NULL)
+ clif_send(buf,packet_db[0x16d].len,&sd->bl,GUILD);
+ }else
+ clif_send(buf,packet_db[0x16d].len,&g->member[idx].sd->bl,GUILD_WOS);
+ return 0;
+}
+/*==========================================
+ * ギルドマスター通知(14dへの応答)
+ *------------------------------------------
+ */
+int clif_guild_masterormember(struct map_session_data *sd)
+{
+ int type=0x57,fd;
+ struct guild *g;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ g=guild_search(sd->status.guild_id);
+ if(g!=NULL && strcmp(g->master,sd->status.name)==0)
+ type=0xd7;
+ WFIFOW(fd,0)=0x14e;
+ WFIFOL(fd,2)=type;
+ WFIFOSET(fd,packet_db[0x14e].len);
+ return 0;
+}
+/*==========================================
+ * Basic Info (Territories [Valaris])
+ *------------------------------------------
+ */
+int clif_guild_basicinfo(struct map_session_data *sd)
+{
+ int fd,i,t=0;
+ struct guild *g;
+ struct guild_castle *gc=NULL;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ g=guild_search(sd->status.guild_id);
+ if(g==NULL)
+ return 0;
+
+ WFIFOW(fd, 0)=0x1b6;//0x150;
+ WFIFOL(fd, 2)=g->guild_id;
+ WFIFOL(fd, 6)=g->guild_lv;
+ WFIFOL(fd,10)=g->connect_member;
+ WFIFOL(fd,14)=g->max_member;
+ WFIFOL(fd,18)=g->average_lv;
+ WFIFOL(fd,22)=g->exp;
+ WFIFOL(fd,26)=g->next_exp;
+ WFIFOL(fd,30)=0; // 上納
+ WFIFOL(fd,34)=0; // VW(性格の悪さ?:性向グラフ左右)
+ WFIFOL(fd,38)=0; // RF(正義の度合い?:性向グラフ上下)
+ WFIFOL(fd,42)=0; // 人数?
+ memcpy(WFIFOP(fd,46),g->name,24);
+ memcpy(WFIFOP(fd,70),g->master,24);
+
+ for(i=0;i<MAX_GUILDCASTLE;i++){
+ gc=guild_castle_search(i);
+ if(!gc) continue;
+ if(g->guild_id == gc->guild_id) t++;
+ }
+
+ if (t==1) memcpy(WFIFOP(fd,94),"One Castle",20);
+ else if (t==2) memcpy(WFIFOP(fd,94),"Two Castles",20);
+ else if (t==3) memcpy(WFIFOP(fd,94),"Three Castles",20);
+ else if (t==4) memcpy(WFIFOP(fd,94),"Four Castles",20);
+ else if (t==5) memcpy(WFIFOP(fd,94),"Five Castles",20);
+ else if (t==6) memcpy(WFIFOP(fd,94),"Six Castles",20);
+ else if (t==7) memcpy(WFIFOP(fd,94),"Seven Castles",20);
+ else if (t==8) memcpy(WFIFOP(fd,94),"Eight Castles",20);
+ else if (t==9) memcpy(WFIFOP(fd,94),"Nine Castles",20);
+ else if (t==10) memcpy(WFIFOP(fd,94),"Ten Castles",20);
+ else if (t==11) memcpy(WFIFOP(fd,94),"Eleven Castles",20);
+ else if (t==12) memcpy(WFIFOP(fd,94),"Twelve Castles",20);
+ else if (t==13) memcpy(WFIFOP(fd,94),"Thirteen Castles",20);
+ else if (t==14) memcpy(WFIFOP(fd,94),"Fourteen Castles",20);
+ else if (t==15) memcpy(WFIFOP(fd,94),"Fifteen Castles",20);
+ else if (t==16) memcpy(WFIFOP(fd,94),"Sixteen Castles",20);
+ else if (t==17) memcpy(WFIFOP(fd,94),"Seventeen Castles",20);
+ else if (t==18) memcpy(WFIFOP(fd,94),"Eighteen Castles",20);
+ else if (t==19) memcpy(WFIFOP(fd,94),"Nineteen Castles",20);
+ else if (t==20) memcpy(WFIFOP(fd,94),"Twenty Castles",20);
+ else if (t==21) memcpy(WFIFOP(fd,94),"Twenty One Castles",20);
+ else if (t==22) memcpy(WFIFOP(fd,94),"Twenty Two Castles",20);
+ else if (t==23) memcpy(WFIFOP(fd,94),"Twenty Three Castles",20);
+ else if (t==24) memcpy(WFIFOP(fd,94),"Twenty Four Castles",20);
+ else if (t==MAX_GUILDCASTLE) memcpy(WFIFOP(fd,94),"Total Domination",20);
+ else memcpy(WFIFOP(fd,94),"None Taken",20);
+
+ WFIFOSET(fd,packet_db[WFIFOW(fd,0)].len);
+ clif_guild_emblem(sd,g); // Guild emblem vanish fix [Valaris]
+ return 0;
+}
+
+/*==========================================
+ * ギルド同盟/敵対情報
+ *------------------------------------------
+ */
+int clif_guild_allianceinfo(struct map_session_data *sd)
+{
+ int fd,i,c;
+ struct guild *g;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ g=guild_search(sd->status.guild_id);
+ if(g==NULL)
+ return 0;
+ WFIFOW(fd, 0)=0x14c;
+ for(i=c=0;i<MAX_GUILDALLIANCE;i++){
+ struct guild_alliance *a=&g->alliance[i];
+ if(a->guild_id>0){
+ WFIFOL(fd,c*32+4)=a->opposition;
+ WFIFOL(fd,c*32+8)=a->guild_id;
+ memcpy(WFIFOP(fd,c*32+12),a->name,24);
+ c++;
+ }
+ }
+ WFIFOW(fd, 2)=c*32+4;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ return 0;
+}
+
+/*==========================================
+ * ギルドメンバーリスト
+ *------------------------------------------
+ */
+int clif_guild_memberlist(struct map_session_data *sd)
+{
+ int fd;
+ int i,c;
+ struct guild *g;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ g=guild_search(sd->status.guild_id);
+ if(g==NULL)
+ return 0;
+
+ WFIFOW(fd, 0)=0x154;
+ for(i=0,c=0;i<g->max_member;i++){
+ struct guild_member *m=&g->member[i];
+ if(m->account_id==0)
+ continue;
+ WFIFOL(fd,c*104+ 4)=m->account_id;
+ WFIFOL(fd,c*104+ 8)=m->char_id;
+ WFIFOW(fd,c*104+12)=m->hair;
+ WFIFOW(fd,c*104+14)=m->hair_color;
+ WFIFOW(fd,c*104+16)=m->gender;
+ WFIFOW(fd,c*104+18)=m->class;
+ WFIFOW(fd,c*104+20)=m->lv;
+ WFIFOL(fd,c*104+22)=m->exp;
+ WFIFOL(fd,c*104+26)=m->online;
+ WFIFOL(fd,c*104+30)=m->position;
+ memset(WFIFOP(fd,c*104+34),0,50); // メモ?
+ memcpy(WFIFOP(fd,c*104+84),m->name,24);
+ c++;
+ }
+ WFIFOW(fd, 2)=c*104+4;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ return 0;
+}
+/*==========================================
+ * ギルド役職名リスト
+ *------------------------------------------
+ */
+int clif_guild_positionnamelist(struct map_session_data *sd)
+{
+ int i,fd;
+ struct guild *g;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ g=guild_search(sd->status.guild_id);
+ if(g==NULL)
+ return 0;
+ WFIFOW(fd, 0)=0x166;
+ for(i=0;i<MAX_GUILDPOSITION;i++){
+ WFIFOL(fd,i*28+4)=i;
+ memcpy(WFIFOP(fd,i*28+8),g->position[i].name,24);
+ }
+ WFIFOW(fd,2)=i*28+4;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ return 0;
+}
+/*==========================================
+ * ギルド役職情報リスト
+ *------------------------------------------
+ */
+int clif_guild_positioninfolist(struct map_session_data *sd)
+{
+ int i,fd;
+ struct guild *g;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ g=guild_search(sd->status.guild_id);
+ if(g==NULL)
+ return 0;
+ WFIFOW(fd, 0)=0x160;
+ for(i=0;i<MAX_GUILDPOSITION;i++){
+ struct guild_position *p=&g->position[i];
+ WFIFOL(fd,i*16+ 4)=i;
+ WFIFOL(fd,i*16+ 8)=p->mode;
+ WFIFOL(fd,i*16+12)=i;
+ WFIFOL(fd,i*16+16)=p->exp_mode;
+ }
+ WFIFOW(fd, 2)=i*16+4;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ return 0;
+}
+/*==========================================
+ * ギルド役職変更通知
+ *------------------------------------------
+ */
+int clif_guild_positionchanged(struct guild *g,int idx)
+{
+ struct map_session_data *sd;
+ unsigned char buf[128];
+
+ nullpo_retr(0, g);
+
+ WBUFW(buf, 0)=0x174;
+ WBUFW(buf, 2)=44;
+ WBUFL(buf, 4)=idx;
+ WBUFL(buf, 8)=g->position[idx].mode;
+ WBUFL(buf,12)=idx;
+ WBUFL(buf,16)=g->position[idx].exp_mode;
+ memcpy(WBUFP(buf,20),g->position[idx].name,24);
+ if( (sd=guild_getavailablesd(g))!=NULL )
+ clif_send(buf,WBUFW(buf,2),&sd->bl,GUILD);
+ return 0;
+}
+/*==========================================
+ * ギルドメンバ変更通知
+ *------------------------------------------
+ */
+int clif_guild_memberpositionchanged(struct guild *g,int idx)
+{
+ struct map_session_data *sd;
+ unsigned char buf[64];
+
+ nullpo_retr(0, g);
+
+ WBUFW(buf, 0)=0x156;
+ WBUFW(buf, 2)=16;
+ WBUFL(buf, 4)=g->member[idx].account_id;
+ WBUFL(buf, 8)=g->member[idx].char_id;
+ WBUFL(buf,12)=g->member[idx].position;
+ if( (sd=guild_getavailablesd(g))!=NULL )
+ clif_send(buf,WBUFW(buf,2),&sd->bl,GUILD);
+ return 0;
+}
+/*==========================================
+ * ギルドエンブレム送信
+ *------------------------------------------
+ */
+int clif_guild_emblem(struct map_session_data *sd,struct guild *g)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, g);
+
+ fd=sd->fd;
+
+ if(g->emblem_len<=0)
+ return 0;
+ WFIFOW(fd,0)=0x152;
+ WFIFOW(fd,2)=g->emblem_len+12;
+ WFIFOL(fd,4)=g->guild_id;
+ WFIFOL(fd,8)=g->emblem_id;
+ memcpy(WFIFOP(fd,12),g->emblem_data,g->emblem_len);
+ WFIFOSET(fd,WFIFOW(fd,2));
+ return 0;
+}
+/*==========================================
+ * ギルドスキル送信
+ *------------------------------------------
+ */
+int clif_guild_skillinfo(struct map_session_data *sd)
+{
+ int fd;
+ int i,id,c,up=1;
+ struct guild *g;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ g=guild_search(sd->status.guild_id);
+ if(g==NULL)
+ return 0;
+ WFIFOW(fd,0)=0x0162;
+ WFIFOW(fd,4)=g->skill_point;
+ for(i=c=0;i<MAX_GUILDSKILL;i++){
+ if(g->skill[i].id>0){
+ WFIFOW(fd,c*37+ 6) = id = g->skill[i].id;
+ WFIFOW(fd,c*37+ 8) = guild_skill_get_inf(id);
+ WFIFOW(fd,c*37+10) = 0;
+ WFIFOW(fd,c*37+12) = g->skill[i].lv;
+ WFIFOW(fd,c*37+14) = guild_skill_get_sp(id,g->skill[i].lv);
+ WFIFOW(fd,c*37+16) = guild_skill_get_range(id);
+ memset(WFIFOP(fd,c*37+18),0,24);
+ if(g->skill[i].lv < guild_skill_get_max(id)) {
+ //Kafra and Guardian changed to require Approval [Sara]
+ if (g->skill[i].id == GD_KAFRACONTACT && guild_checkskill(g,GD_APPROVAL) <= 0)
+ up = 0;
+ else if (g->skill[i].id == GD_GUARDIANRESEARCH && guild_checkskill(g,GD_APPROVAL) <= 0)
+ up = 0;
+ //Glory skill requirements -- Pretty sure correct [Sara]
+ else if (g->skill[i].id == GD_LEADERSHIP && guild_checkskill(g,GD_GLORYGUILD) <= 0)
+ up = 0;
+ else if (g->skill[i].id == GD_GLORYWOUNDS && guild_checkskill(g,GD_GLORYGUILD) <= 0)
+ up = 0;
+ else if (g->skill[i].id == GD_SOULCOLD && guild_checkskill(g,GD_GLORYWOUNDS) <= 0)
+ up = 0;
+ else if (g->skill[i].id == GD_HAWKEYES && guild_checkskill(g,GD_LEADERSHIP) <= 0)
+ up = 0;
+ //Activated skill requirements -- Just guesses [Sara]
+ else if (g->skill[i].id == GD_BATTLEORDER && guild_checkskill(g,GD_APPROVAL) <= 0)
+ up = 0;
+ else if (g->skill[i].id == GD_REGENERATION && guild_checkskill(g,GD_APPROVAL) <= 0)
+ up = 0;
+ else if (g->skill[i].id == GD_RESTORE && guild_checkskill(g,GD_REGENERATION) <= 0)
+ up = 0;
+ else if (g->skill[i].id == GD_EMERGENCYCALL && guild_checkskill(g,GD_APPROVAL) <= 0)
+ up = 0;
+ if (g->skill[i].id == GD_GUARDUP && guild_checkskill(g,GD_GUARDIANRESEARCH) <= 0)
+ up = 0;
+ //Unadded yet? Has extension description in kRO tables
+ else if (g->skill[i].id == GD_DEVELOPMENT)
+ up = 0;
+ else
+ up = 1;
+ }
+ else {
+ up = 0;
+ }
+ WFIFOB(fd,c*37+42)= up;
+ c++;
+ }
+ }
+ WFIFOW(fd,2)=c*37+6;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ return 0;
+}
+/*==========================================
+ * ギルド告知送信
+ *------------------------------------------
+ */
+int clif_guild_notice(struct map_session_data *sd,struct guild *g)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, g);
+
+ fd=sd->fd;
+ if(*g->mes1==0 && *g->mes2==0)
+ return 0;
+ WFIFOW(fd,0)=0x16f;
+ memcpy(WFIFOP(fd,2),g->mes1,60);
+ memcpy(WFIFOP(fd,62),g->mes2,120);
+ WFIFOSET(fd,packet_db[0x16f].len);
+ return 0;
+}
+
+/*==========================================
+ * ギルドメンバ勧誘
+ *------------------------------------------
+ */
+int clif_guild_invite(struct map_session_data *sd,struct guild *g)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, g);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x16a;
+ WFIFOL(fd,2)=g->guild_id;
+ memcpy(WFIFOP(fd,6),g->name,24);
+ WFIFOSET(fd,packet_db[0x16a].len);
+ return 0;
+}
+/*==========================================
+ * ギルドメンバ勧誘結果
+ *------------------------------------------
+ */
+int clif_guild_inviteack(struct map_session_data *sd,int flag)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x169;
+ WFIFOB(fd,2)=flag;
+ WFIFOSET(fd,packet_db[0x169].len);
+ return 0;
+}
+/*==========================================
+ * ギルドメンバ脱退通知
+ *------------------------------------------
+ */
+int clif_guild_leave(struct map_session_data *sd,const char *name,const char *mes)
+{
+ unsigned char buf[128];
+
+ nullpo_retr(0, sd);
+
+ WBUFW(buf, 0)=0x15a;
+ memcpy(WBUFP(buf, 2),name,24);
+ memcpy(WBUFP(buf,26),mes,40);
+ clif_send(buf,packet_db[0x15a].len,&sd->bl,GUILD);
+ return 0;
+}
+/*==========================================
+ * ギルドメンバ追放通知
+ *------------------------------------------
+ */
+int clif_guild_explusion(struct map_session_data *sd,const char *name,const char *mes,
+ int account_id)
+{
+ unsigned char buf[128];
+
+ nullpo_retr(0, sd);
+
+ WBUFW(buf, 0)=0x15c;
+ memcpy(WBUFP(buf, 2),name,24);
+ memcpy(WBUFP(buf,26),mes,40);
+ memcpy(WBUFP(buf,66),"dummy",24);
+ clif_send(buf,packet_db[0x15c].len,&sd->bl,GUILD);
+ return 0;
+}
+/*==========================================
+ * ギルド追放メンバリスト
+ *------------------------------------------
+ */
+int clif_guild_explusionlist(struct map_session_data *sd)
+{
+ int fd;
+ int i,c;
+ struct guild *g;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ g=guild_search(sd->status.guild_id);
+ if(g==NULL)
+ return 0;
+ WFIFOW(fd,0)=0x163;
+ for(i=c=0;i<MAX_GUILDEXPLUSION;i++){
+ struct guild_explusion *e=&g->explusion[i];
+ if(e->account_id>0){
+ memcpy(WFIFOP(fd,c*88+ 4),e->name,24);
+ memcpy(WFIFOP(fd,c*88+28),e->acc,24);
+ memcpy(WFIFOP(fd,c*88+52),e->mes,44);
+ c++;
+ }
+ }
+ WFIFOW(fd,2)=c*88+4;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ return 0;
+}
+
+/*==========================================
+ * ギルド会話
+ *------------------------------------------
+ */
+int clif_guild_message(struct guild *g,int account_id,const char *mes,int len)
+{
+ struct map_session_data *sd;
+ unsigned char lbuf[255];
+ unsigned char *buf = lbuf;
+ if (len + 32 >= sizeof(lbuf))
+ buf = malloc(len + 32);
+ WBUFW(buf, 0)=0x17f;
+ WBUFW(buf, 2)=len+4;
+ memcpy(WBUFP(buf,4),mes,len);
+
+ if( (sd=guild_getavailablesd(g))!=NULL )
+ clif_send(buf,WBUFW(buf,2),&sd->bl,GUILD);
+ if ( buf != lbuf)
+ free(buf);
+ return 0;
+}
+/*==========================================
+ * ギルドスキル割り振り通知
+ *------------------------------------------
+ */
+int clif_guild_skillup(struct map_session_data *sd,int skill_num,int lv)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0) = 0x10e;
+ WFIFOW(fd,2) = skill_num;
+ WFIFOW(fd,4) = lv;
+ WFIFOW(fd,6) = guild_skill_get_sp(skill_num,lv);
+ WFIFOW(fd,8) = guild_skill_get_range(skill_num);
+ WFIFOB(fd,10) = 1;
+ WFIFOSET(fd,11);
+ return 0;
+}
+/*==========================================
+ * ギルド同盟要請
+ *------------------------------------------
+ */
+int clif_guild_reqalliance(struct map_session_data *sd,int account_id,const char *name)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x171;
+ WFIFOL(fd,2)=account_id;
+ memcpy(WFIFOP(fd,6),name,24);
+ WFIFOSET(fd,packet_db[0x171].len);
+ return 0;
+}
+/*==========================================
+ * ギルド同盟結果
+ *------------------------------------------
+ */
+int clif_guild_allianceack(struct map_session_data *sd,int flag)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x173;
+ WFIFOL(fd,2)=flag;
+ WFIFOSET(fd,packet_db[0x173].len);
+ return 0;
+}
+/*==========================================
+ * ギルド関係解消通知
+ *------------------------------------------
+ */
+int clif_guild_delalliance(struct map_session_data *sd,int guild_id,int flag)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x184;
+ WFIFOL(fd,2)=guild_id;
+ WFIFOL(fd,6)=flag;
+ WFIFOSET(fd,packet_db[0x184].len);
+ return 0;
+}
+/*==========================================
+ * ギルド敵対結果
+ *------------------------------------------
+ */
+int clif_guild_oppositionack(struct map_session_data *sd,int flag)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x181;
+ WFIFOB(fd,2)=flag;
+ WFIFOSET(fd,packet_db[0x181].len);
+ return 0;
+}
+/*==========================================
+ * ギルド関係追加
+ *------------------------------------------
+ */
+/*int clif_guild_allianceadded(struct guild *g,int idx)
+{
+ unsigned char buf[64];
+ WBUFW(fd,0)=0x185;
+ WBUFL(fd,2)=g->alliance[idx].opposition;
+ WBUFL(fd,6)=g->alliance[idx].guild_id;
+ memcpy(WBUFP(fd,10),g->alliance[idx].name,24);
+ clif_send(buf,packet_db[0x185].len,guild_getavailablesd(g),GUILD);
+ return 0;
+}*/
+
+/*==========================================
+ * ギルド解散通知
+ *------------------------------------------
+ */
+int clif_guild_broken(struct map_session_data *sd,int flag)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x15e;
+ WFIFOL(fd,2)=flag;
+ WFIFOSET(fd,packet_db[0x15e].len);
+ return 0;
+}
+
+/*==========================================
+ * エモーション
+ *------------------------------------------
+ */
+void clif_emotion(struct block_list *bl,int type)
+{
+ unsigned char buf[8];
+
+ nullpo_retv(bl);
+
+ WBUFW(buf,0)=0xc0;
+ WBUFL(buf,2)=bl->id;
+ WBUFB(buf,6)=type;
+ clif_send(buf,packet_db[0xc0].len,bl,AREA);
+}
+
+/*==========================================
+ * トーキーボックス
+ *------------------------------------------
+ */
+void clif_talkiebox(struct block_list *bl,char* talkie)
+{
+ unsigned char buf[86];
+
+ nullpo_retv(bl);
+
+ WBUFW(buf,0)=0x191;
+ WBUFL(buf,2)=bl->id;
+ memcpy(WBUFP(buf,6),talkie,80);
+ clif_send(buf,packet_db[0x191].len,bl,AREA);
+}
+
+/*==========================================
+ * 結婚エフェクト
+ *------------------------------------------
+ */
+void clif_wedding_effect(struct block_list *bl) {
+ unsigned char buf[6];
+
+ nullpo_retv(bl);
+
+ WBUFW(buf,0) = 0x1ea;
+ WBUFL(buf,2) = bl->id;
+ clif_send(buf, packet_db[0x1ea].len, bl, AREA);
+}
+/*==========================================
+ * あなたに逢いたい使用時名前叫び
+ *------------------------------------------
+
+void clif_callpartner(struct map_session_data *sd)
+{
+ unsigned char buf[26];
+ char *p;
+
+ nullpo_retv(sd);
+
+ if(sd->status.partner_id){
+ WBUFW(buf,0)=0x1e6;
+ p = map_charid2nick(sd->status.partner_id);
+ if(p){
+ memcpy(WBUFP(buf,2),p,24);
+ }else{
+ map_reqchariddb(sd,sd->status.partner_id);
+ chrif_searchcharid(sd->status.partner_id);
+ WBUFB(buf,2) = 0;
+ }
+ clif_send(buf,packet_db[0x1e6]&sd->bl,AREA);
+ }
+ return;
+}
+*/
+/*==========================================
+ * 座る
+ *------------------------------------------
+ */
+void clif_sitting(int fd, struct map_session_data *sd)
+{
+ unsigned char buf[64];
+
+ nullpo_retv(sd);
+
+ WBUFW(buf, 0) = 0x8a;
+ WBUFL(buf, 2) = sd->bl.id;
+ WBUFB(buf,26) = 2;
+ clif_send(buf, packet_db[0x8a].len, &sd->bl, AREA);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int clif_disp_onlyself(struct map_session_data *sd, char *mes, int len)
+{
+ unsigned char lbuf[255];
+ unsigned char *buf = (len + 32 >= sizeof(lbuf)) ? malloc(len + 32) : lbuf;
+
+ nullpo_retr(0, sd);
+
+ WBUFW(buf, 0) = 0x17f;
+ WBUFW(buf, 2) = len + 8;
+ memcpy(WBUFP(buf,4), mes, len + 4);
+
+ clif_send(buf, WBUFW(buf,2), &sd->bl, SELF);
+
+ if (buf != lbuf)
+ free(buf);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+
+int clif_GM_kickack(struct map_session_data *sd, int id)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd = sd->fd;
+ WFIFOW(fd,0) = 0xcd;
+ WFIFOL(fd,2) = id;
+ WFIFOSET(fd,packet_db[0xcd].len);
+ return 0;
+}
+
+int clif_GM_kick(struct map_session_data *sd,struct map_session_data *tsd,int type)
+{
+ int fd;
+ nullpo_retr(0, tsd);
+
+ if(type)
+ clif_GM_kickack(sd,tsd->status.account_id);
+ tsd->opt1 = tsd->opt2 = 0;
+ fd = tsd->fd;
+ WFIFOW(fd,0) = 0x18b;
+ WFIFOW(fd,2) = 0;
+ WFIFOSET(fd,packet_db[0x18b].len);
+ clif_setwaitclose(fd);
+
+ return 0;
+}
+/*==========================================
+ * Wis拒否許可応答
+ *------------------------------------------
+ */
+int clif_wisexin(struct map_session_data *sd,int type,int flag)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xd1;
+ WFIFOB(fd,2)=type;
+ WFIFOB(fd,3)=flag;
+ WFIFOSET(fd,packet_db[0xd1].len);
+
+ return 0;
+}
+/*==========================================
+ * Wis全拒否許可応答
+ *------------------------------------------
+ */
+int clif_wisall(struct map_session_data *sd,int type,int flag)
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0xd2;
+ WFIFOB(fd,2)=type;
+ WFIFOB(fd,3)=flag;
+ WFIFOSET(fd,packet_db[0xd2].len);
+
+ return 0;
+}
+/*==========================================
+ * サウンドエフェクト
+ *------------------------------------------
+ */
+void clif_soundeffect(struct map_session_data *sd,struct block_list *bl,char *name,int type)
+{
+ int fd;
+
+ nullpo_retv(sd);
+ nullpo_retv(bl);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x1d3;
+ memcpy(WFIFOP(fd,2),name,24);
+ WFIFOB(fd,26)=type;
+ WFIFOL(fd,27)=0;
+ WFIFOL(fd,31)=bl->id;
+ WFIFOSET(fd,packet_db[0x1d3].len);
+
+ return;
+}
+// displaying special effects (npcs, weather, etc) [Valaris]
+int clif_specialeffect(struct block_list *bl, int type, int flag) {
+ unsigned char buf[24];
+
+ nullpo_retr(0, bl);
+
+ memset(buf, 0, packet_db[0x1f3].len);
+
+ WBUFW(buf,0) = 0x1f3;
+ WBUFL(buf,2) = bl->id;
+ WBUFL(buf,6) = type;
+
+ if (flag==2) {
+ struct map_session_data *sd=NULL;
+ int i;
+ for(i=0; i < fd_max; i++) {
+ if (session[i] && (sd = session[i]->session_data) != NULL && sd->state.auth && sd->bl.m == bl->m)
+ clif_specialeffect(&sd->bl,type,1);
+ }
+ }
+
+ else if (flag==1)
+ clif_send(buf, packet_db[0x1f3].len, bl, SELF);
+ else if (!flag)
+ clif_send(buf, packet_db[0x1f3].len, bl, AREA);
+
+ return 0;
+
+}
+// ------------
+// clif_parse_*
+// ------------
+// パケット読み取って色々操作
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_WantToConnection(int fd, struct map_session_data *sd, int cmd)
+{
+ struct map_session_data *old_sd;
+ int account_id,char_id,login_id1,sex;
+ unsigned int client_tick;
+
+ if (sd) {
+ if (battle_config.error_log)
+ printf("clif_parse_WantToConnection : invalid request?\n");
+ return;
+ }
+
+ sd = session[fd]->session_data = calloc(sizeof(*sd), 1);
+ if (sd == NULL) {
+ printf("out of memory : clif_parse_WantToConnection\n");
+ exit(1);
+ }
+ sd->fd = fd;
+
+ account_id = RFIFOL(fd,packet_db[cmd].pos[0]);
+ char_id = RFIFOL(fd,packet_db[cmd].pos[1]);
+ login_id1 = RFIFOL(fd,packet_db[cmd].pos[2]);
+ client_tick = RFIFOL(fd,packet_db[cmd].pos[3]);
+ sex = RFIFOB(fd,packet_db[cmd].pos[4]);
+
+ pc_setnewpc(sd,account_id,char_id,login_id1,client_tick,sex,fd);
+ if((old_sd=map_id2sd(account_id)) != NULL){
+ // if same account already connected, we disconnect the 2 sessions
+ old_sd->new_fd=fd;
+ } else {
+ map_addiddb(&sd->bl);
+ }
+
+ chrif_authreq(sd);
+
+ WFIFOL(fd,0)=sd->bl.id;
+ WFIFOSET(fd,4);
+
+ return;
+}
+
+/*==========================================
+ * 007d クライアント側マップ読み込み完了
+ * map侵入時に必要なデータを全て送りつける
+ *------------------------------------------
+ */
+void clif_parse_LoadEndAck(int fd,struct map_session_data *sd, int cmd)
+{
+// struct item_data* item;
+ int i;
+ nullpo_retv(sd);
+
+ if(sd->bl.prev != NULL)
+ return;
+
+ // 接続ok時
+ //clif_authok();
+ if(sd->npc_id) npc_event_dequeue(sd);
+ clif_skillinfoblock(sd);
+ pc_checkitem(sd);
+ //guild_info();
+
+ // loadendack時
+ // next exp
+ clif_updatestatus(sd,SP_NEXTBASEEXP);
+ clif_updatestatus(sd,SP_NEXTJOBEXP);
+ // skill point
+ clif_updatestatus(sd,SP_SKILLPOINT);
+ // item
+ clif_itemlist(sd);
+ clif_equiplist(sd);
+ // cart
+ if(pc_iscarton(sd)){
+ clif_cart_itemlist(sd);
+ clif_cart_equiplist(sd);
+ clif_updatestatus(sd,SP_CARTINFO);
+ }
+ // param all
+ clif_initialstatus(sd);
+ // party
+ party_send_movemap(sd);
+ // guild
+ guild_send_memberinfoshort(sd,1);
+ // 119
+ // 78
+
+ if(battle_config.pc_invincible_time > 0) {
+ if(map[sd->bl.m].flag.gvg)
+ pc_setinvincibletimer(sd,battle_config.pc_invincible_time<<1);
+ else
+ pc_setinvincibletimer(sd,battle_config.pc_invincible_time);
+ }
+
+ map_addblock(&sd->bl); // ブロック登録
+ clif_spawnpc(sd); // spawn
+
+ // weight max , now
+ clif_updatestatus(sd,SP_MAXWEIGHT);
+ clif_updatestatus(sd,SP_WEIGHT);
+
+ // pvp
+ if(sd->pvp_timer!=-1 && !battle_config.pk_mode)
+ delete_timer(sd->pvp_timer,pc_calc_pvprank_timer);
+ if(map[sd->bl.m].flag.pvp){
+ if(!battle_config.pk_mode) { // remove pvp stuff for pk_mode [Valaris]
+ sd->pvp_timer=add_timer(gettick()+200,pc_calc_pvprank_timer,sd->bl.id,0);
+ sd->pvp_rank=0;
+ sd->pvp_lastusers=0;
+ sd->pvp_point=5;
+ }
+ clif_set0199(sd->fd,1);
+ } else {
+ sd->pvp_timer=-1;
+ }
+ if(map[sd->bl.m].flag.gvg) {
+ clif_set0199(sd->fd,3);
+ }
+
+ // pet
+ if(sd->status.pet_id > 0 && sd->pd && sd->pet.intimate > 0) {
+ map_addblock(&sd->pd->bl);
+ clif_spawnpet(sd->pd);
+ clif_send_petdata(sd,0,0);
+ clif_send_petdata(sd,5,0x14);
+ clif_send_petstatus(sd);
+ }
+
+ if(sd->state.connect_new) {
+ sd->state.connect_new = 0;
+ if(sd->status.class != sd->view_class)
+ clif_changelook(&sd->bl,LOOK_BASE,sd->view_class);
+ if(sd->status.pet_id > 0 && sd->pd && sd->pet.intimate > 900)
+ clif_pet_emotion(sd->pd,(sd->pd->class - 100)*100 + 50 + pet_hungry_val(sd));
+
+/* Stop players from spawning inside castles [Valaris] */
+
+ {
+ struct guild_castle *gc=guild_mapname2gc(map[sd->bl.m].name);
+ if (gc)
+ pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,2);
+ }
+
+/* End Addition [Valaris] */
+
+ }
+
+ // view equipment item
+#if PACKETVER < 4
+ clif_changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon);
+ clif_changelook(&sd->bl,LOOK_SHIELD,sd->status.shield);
+#else
+ clif_changelook(&sd->bl,LOOK_WEAPON,0);
+#endif
+ if(battle_config.save_clothcolor==1 && sd->status.clothes_color > 0)
+ clif_changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->status.clothes_color);
+
+ if(sd->status.hp<sd->status.max_hp>>2 && pc_checkskill(sd,SM_AUTOBERSERK)>0 &&
+ (sd->sc_data[SC_PROVOKE].timer==-1 || sd->sc_data[SC_PROVOKE].val2==0 ))
+ // オートバーサーク発動
+ skill_status_change_start(&sd->bl,SC_PROVOKE,10,1,0,0,0,0);
+
+// if(time(&timer) < ((weddingtime=pc_readglobalreg(sd,"PC_WEDDING_TIME")) + 3600))
+// skill_status_change_start(&sd->bl,SC_WEDDING,0,weddingtime,0,0,36000,0);
+
+ if(battle_config.muting_players && sd->status.manner < 0)
+ skill_status_change_start(&sd->bl,SC_NOCHAT,0,0,0,0,0,0);
+
+ // option
+ clif_changeoption(&sd->bl);
+ if(sd->sc_data[SC_TRICKDEAD].timer != -1)
+ skill_status_change_end(&sd->bl,SC_TRICKDEAD,-1);
+ if(sd->sc_data[SC_SIGNUMCRUCIS].timer != -1 && !battle_check_undead(7,sd->def_ele))
+ skill_status_change_end(&sd->bl,SC_SIGNUMCRUCIS,-1);
+ if(sd->special_state.infinite_endure && sd->sc_data[SC_ENDURE].timer == -1)
+ skill_status_change_start(&sd->bl,SC_ENDURE,10,1,0,0,0,0);
+ for(i=0;i<MAX_INVENTORY;i++){
+ if(sd->status.inventory[i].equip && sd->status.inventory[i].equip & 0x0002 && sd->status.inventory[i].attribute==1)
+ skill_status_change_start(&sd->bl,SC_BROKNWEAPON,0,0,0,0,0,0);
+ if(sd->status.inventory[i].equip && sd->status.inventory[i].equip & 0x0010 && sd->status.inventory[i].attribute==1)
+ skill_status_change_start(&sd->bl,SC_BROKNARMOR,0,0,0,0,0,0);
+ }
+
+ map_foreachinarea(clif_getareachar,sd->bl.m,sd->bl.x-AREA_SIZE,sd->bl.y-AREA_SIZE,sd->bl.x+AREA_SIZE,sd->bl.y+AREA_SIZE,0,sd);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_TickSend(int fd, struct map_session_data *sd, int cmd) {
+ nullpo_retv(sd);
+
+ sd->client_tick=RFIFOL(fd,packet_db[cmd].pos[0]);
+ sd->server_tick=gettick();
+ clif_servertick(sd);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_WalkToXY(int fd, struct map_session_data *sd, int cmd) {
+ int x, y;
+
+ nullpo_retv(sd);
+
+ if (pc_isdead(sd)) {
+ clif_clearchar_area(&sd->bl, 1);
+ return;
+ }
+
+ if (sd->npc_id != 0 || sd->vender_id != 0)
+ return;
+
+ if (sd->skilltimer != -1 && pc_checkskill(sd, SA_FREECAST) <= 0) // フリーキャスト
+ return;
+
+ if (sd->chatID)
+ return;
+
+ if (sd->canmove_tick > gettick())
+ return;
+
+ // ステータス異常やハイディング中(トンネルドライブ無)で動けない
+ if ((sd->opt1 > 0 && sd->opt1 != 6) ||
+ sd->sc_data[SC_ANKLE].timer !=-1 || //アンクルスネア
+ sd->sc_data[SC_AUTOCOUNTER].timer !=-1 || //オートカウンター
+ sd->sc_data[SC_TRICKDEAD].timer !=-1 || //死んだふり
+ sd->sc_data[SC_BLADESTOP].timer !=-1 || //白刃取り
+ sd->sc_data[SC_SPIDERWEB].timer !=-1 || //スパイダーウェッブ
+ (sd->sc_data[SC_DANCING].timer !=-1 && sd->sc_data[SC_DANCING].val4)) //合奏スキル演奏中は動けない
+ return;
+ if ((sd->status.option & 2) && pc_checkskill(sd, RG_TUNNELDRIVE) <= 0)
+ return;
+
+ if (sd->invincible_timer != -1)
+ pc_delinvincibletimer(sd);
+
+ pc_stopattack(sd);
+
+ x = RFIFOB(fd,packet_db[cmd].pos[0])*4+(RFIFOB(fd,packet_db[cmd].pos[0]+1)>>6);
+ y = ((RFIFOB(fd,packet_db[cmd].pos[0]+1)&0x3f)<<4)+(RFIFOB(fd,packet_db[cmd].pos[0]+2)>>4);
+
+ pc_walktoxy(sd,x,y);
+
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_QuitGame(int fd, struct map_session_data *sd, int cmd) {
+ unsigned int tick=gettick();
+ struct skill_unit_group* sg;
+
+ nullpo_retv(sd);
+
+ WFIFOW(fd,0) = 0x18b;
+ if ((!pc_isdead(sd) && (sd->opt1 || (sd->opt2 && !(night_flag == 1 && sd->opt2 == STATE_BLIND)))) ||
+ sd->skilltimer != -1 ||
+ (DIFF_TICK(tick , sd->canact_tick) < 0) ||
+ (sd->sc_data && sd->sc_data[SC_DANCING].timer!=-1 && sd->sc_data[SC_DANCING].val4 && (sg=(struct skill_unit_group *)sd->sc_data[SC_DANCING].val2) && sg->src_id == sd->bl.id)) {
+ WFIFOW(fd,2)=1;
+ WFIFOSET(fd,packet_db[0x18b].len);
+ return;
+ }
+
+ /* Rovert's prevent logout option fixed [Valaris] */
+ if ((battle_config.prevent_logout && (gettick() - sd->canlog_tick) >= 10000) || (!battle_config.prevent_logout)) {
+ clif_setwaitclose(fd);
+ WFIFOW(fd,2)=0;
+ } else {
+ WFIFOW(fd,2)=1;
+ }
+ WFIFOSET(fd,packet_db[0x18b].len);
+
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd, int cmd) {
+ struct block_list *bl;
+ int account_id;
+
+ account_id = RFIFOL(fd,packet_db[cmd].pos[0]);
+ bl=map_id2bl(account_id);
+ if(bl==NULL)
+ return;
+
+ WFIFOW(fd,0) = 0x95;
+ WFIFOL(fd,2) = account_id;
+
+ switch(bl->type) {
+ case BL_PC:
+ {
+ struct map_session_data *ssd = (struct map_session_data *)bl;
+ struct party *p = NULL;
+ struct guild *g = NULL;
+
+ nullpo_retv(ssd);
+
+ memcpy(WFIFOP(fd,6), ssd->status.name, 24);
+ if (ssd->status.guild_id > 0 && (g = guild_search(ssd->status.guild_id)) != NULL &&
+ (ssd->status.party_id == 0 || (p = party_search(ssd->status.party_id)) != NULL)) {
+ // ギルド所属ならパケット0195を返す
+ int i, ps = -1;
+ for(i = 0; i < g->max_member; i++) {
+ if (g->member[i].account_id == ssd->status.account_id &&
+ g->member[i].char_id == ssd->status.char_id )
+ ps = g->member[i].position;
+ }
+ if (ps >= 0 && ps < MAX_GUILDPOSITION) {
+ WFIFOW(fd, 0) = 0x195;
+ if (p)
+ memcpy(WFIFOP(fd,30), p->name, 24);
+ else
+ WFIFOB(fd,30) = 0;
+ memcpy(WFIFOP(fd,54), g->name,24);
+ memcpy(WFIFOP(fd,78), g->position[ps].name, 24);
+ WFIFOSET(fd,packet_db[0x195].len);
+ break;
+ }
+ }
+ WFIFOSET(fd,packet_db[0x95].len);
+ }
+ break;
+ case BL_PET:
+ memcpy(WFIFOP(fd,6), ((struct pet_data*)bl)->name, 24);
+ WFIFOSET(fd,packet_db[0x95].len);
+ break;
+ case BL_NPC:
+ memcpy(WFIFOP(fd,6), ((struct npc_data*)bl)->name, 24);
+ WFIFOSET(fd,packet_db[0x95].len);
+ break;
+ case BL_MOB:
+ {
+ struct mob_data *md = (struct mob_data *)bl;
+
+ nullpo_retv(md);
+
+ memcpy(WFIFOP(fd,6), md->name, 24);
+ if (md->class >= 1285 && md->class <= 1288) {
+ struct guild *g;
+ struct guild_castle *gc = guild_mapname2gc(map[md->bl.m].name);
+ if (gc && gc->guild_id > 0 && (g = guild_search(gc->guild_id)) != NULL) {
+ WFIFOW(fd, 0) = 0x195;
+ WFIFOB(fd,30) = 0;
+ memcpy(WFIFOP(fd,54), g->name, 24);
+ memcpy(WFIFOP(fd,78), gc->castle_name, 24);
+ WFIFOSET(fd,packet_db[0x195].len);
+ } else {
+ WFIFOSET(fd,packet_db[0x95].len);
+ }
+ } else if (battle_config.show_mob_hp == 1) {
+ char mobhp[50];
+ sprintf(mobhp, "hp: %d/%d", md->hp, mob_db[md->class].max_hp);
+ WFIFOW(fd, 0) = 0x195;
+ memcpy(WFIFOP(fd,30), mobhp, 24);
+ WFIFOB(fd,54) = 0;
+ WFIFOB(fd,78) = 0;
+ WFIFOSET(fd,packet_db[0x195].len);
+ } else {
+ WFIFOSET(fd,packet_db[0x95].len);
+ }
+ }
+ break;
+ default:
+ if (battle_config.error_log)
+ printf("clif_parse_GetCharNameRequest : bad type %d(%d)\n", bl->type, account_id);
+ break;
+ }
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_GlobalMessage(int fd, struct map_session_data *sd, int cmd) { // S 008c <len>.w <str>.?B
+ char *message = (char *) malloc(RFIFOW(fd,2) + 128);
+ char *buf = (char *) malloc(RFIFOW(fd,2) + 4);
+
+ nullpo_retv(sd);
+
+ memset(message, '\0', RFIFOW(fd,packet_db[cmd].pos[0]) + 128);
+ memset(buf, '\0', RFIFOW(fd,packet_db[cmd].pos[0]) + 4);
+
+ if ((is_atcommand(fd, sd, RFIFOP(fd, packet_db[cmd].pos[1]), 0) != AtCommand_None) ||
+ ( sd->sc_data &&
+ (sd->sc_data[SC_BERSERK].timer!=-1 || //バーサーク時は会話も不可
+ sd->sc_data[SC_NOCHAT].timer!=-1 ) )) //チャット禁止
+ {
+ free(message);
+ free(buf);
+ return;
+ }
+
+ //printf("clif_parse_GlobalMessage: message: '%s'.\n", RFIFOP(fd,4));
+ if (strncmp(RFIFOP(fd, packet_db[cmd].pos[1]), sd->status.name, strlen(sd->status.name)) != 0) {
+ printf("Hack on global message: character '%s' (account: %d), use an other name to send a (normal) message.\n", sd->status.name, sd->status.account_id);
+
+ // information is sended to all online GM
+ sprintf(message, "Hack on global message (normal message): character '%s' (account: %d) uses an other name.", sd->status.name, sd->status.account_id);
+ intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message, strlen(message) + 1);
+ if (strlen(RFIFOP(fd, packet_db[cmd].pos[1])) == 0)
+ strcpy(message, " This player sends a void name and a void message.");
+ else
+ sprintf(message, " This player sends (name:message): '%s'.", RFIFOP(fd, packet_db[cmd].pos[1]));
+ intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message, strlen(message) + 1);
+ // message about the ban
+ if (battle_config.ban_spoof_namer > 0)
+ sprintf(message, " This player has been banned for %d minute(s).", battle_config.ban_spoof_namer);
+ else
+ sprintf(message, " This player hasn't been banned (Ban option is disabled).");
+ intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message, strlen(message) + 1);
+
+ // if we ban people
+ if (battle_config.ban_spoof_namer > 0) {
+ chrif_char_ask_name(-1, sd->status.name, 2, 0, 0, 0, 0, battle_config.ban_spoof_namer, 0); // type: 2 - ban (year, month, day, hour, minute, second)
+ clif_setwaitclose(fd); // forced to disconnect because of the hack
+ }
+ // but for the hacker, we display on his screen (he see/look no difference).
+ } else {
+ // send message to others
+ WBUFW(buf,0) = 0x8d;
+ WBUFW(buf,2) = RFIFOW(fd,2) + 4; // len of message - 4 + 8
+ WBUFL(buf,4) = sd->bl.id;
+ memcpy(WBUFP(buf,8), RFIFOP(fd,4), RFIFOW(fd,2) - 4);
+ clif_send(buf, WBUFW(buf,2), &sd->bl, sd->chatID ? CHAT_WOS : AREA_CHAT_WOC);
+ }
+
+ // send back message to the speaker
+ memcpy(WFIFOP(fd,0), RFIFOP(fd,0), RFIFOW(fd,packet_db[cmd].pos[0]));
+ WFIFOW(fd,0) = 0x8e;
+ WFIFOSET(fd, WFIFOW(fd,2));
+
+ free(message);
+ free(buf);
+
+ return;
+}
+
+int clif_message(struct block_list *bl, char* msg)
+{
+ unsigned short msg_len = strlen(msg) + 1;
+ unsigned char buf[256];
+
+ nullpo_retr(0, bl);
+
+ WBUFW(buf, 0) = 0x8d;
+ WBUFW(buf, 2) = msg_len + 8;
+ WBUFL(buf, 4) = bl->id;
+ memcpy(WBUFP(buf, 8), msg, msg_len);
+
+ clif_send(buf, WBUFW(buf,2), bl, AREA);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_MapMove(int fd, struct map_session_data *sd, int cmd) {
+// /m /mapmove (as @rura GM command)
+ char mapname[32];
+ int x,y;
+
+ if (battle_config.atc_gmonly == 0 ||
+ pc_isGM(sd) >= get_atcommand_level(AtCommand_MapMove)) {
+ memcpy(mapname,RFIFOP(fd,packet_db[cmd].pos[0]),16);
+ mapname[16]=0;
+ x=RFIFOW(fd,packet_db[cmd].pos[1]);
+ y=RFIFOW(fd,packet_db[cmd].pos[2]);
+ pc_setpos(sd,mapname,x,y,2);
+ }
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_ChangeDir(int fd, struct map_session_data *sd, int cmd) {
+ short headdir,dir;
+ unsigned char buf[64];
+
+ nullpo_retv(sd);
+
+ headdir=RFIFOW(fd,packet_db[cmd].pos[0]);
+ dir=RFIFOB(fd,packet_db[cmd].pos[1]);
+ pc_setdir(sd,dir,headdir);
+
+ WFIFOW(fd,0)=0x9c;
+ WFIFOL(fd,2)=sd->bl.id;
+ WFIFOW(fd,6)=headdir;
+ WFIFOB(fd,8)=dir;
+ if (sd->disguise > 23 && sd->disguise < 4001) // mob disguises [Valaris]
+ clif_send(buf, packet_db[0x9c].len, &sd->bl, AREA);
+ else
+ clif_send(buf, packet_db[0x9c].len, &sd->bl, AREA_WOS);
+
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_Emotion(int fd, struct map_session_data *sd, int cmd) {
+ int emotion;
+ unsigned char buf[64];
+
+ nullpo_retv(sd);
+
+ if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, NV_BASIC) >= 2) {
+ emotion=RFIFOB(fd,packet_db[cmd].pos[0]);
+ WBUFW(buf,0) = 0xc0;
+ WBUFL(buf,2) = sd->bl.id;
+ WBUFB(buf,6) = emotion;
+ clif_send(buf, packet_db[0xc0].len, &sd->bl, AREA);
+ } else
+ clif_skill_fail(sd, 1, 0, 1);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_HowManyConnections(int fd, struct map_session_data *sd, int cmd) {
+ WFIFOW(fd,0) = 0xc2;
+ WFIFOL(fd,2) = map_getusers();
+ WFIFOSET(fd,packet_db[0xc2].len);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_ActionRequest(int fd, struct map_session_data *sd, int cmd) {
+ unsigned int tick;
+ unsigned char buf[64];
+ int action_type, target_id;
+
+ nullpo_retv(sd);
+
+ if (pc_isdead(sd)) {
+ clif_clearchar_area(&sd->bl, 1);
+ return;
+ }
+ if (sd->npc_id != 0 || sd->opt1 > 0 || sd->status.option & 2 ||
+ (sd->sc_data &&
+ (sd->sc_data[SC_AUTOCOUNTER].timer != -1 || //オートカウンター
+ sd->sc_data[SC_BLADESTOP].timer != -1 || //白刃取り
+ sd->sc_data[SC_DANCING].timer != -1))) //ダンス中
+ return;
+
+ tick = gettick();
+
+ pc_stop_walking(sd, 0);
+ pc_stopattack(sd);
+
+ target_id = RFIFOL(fd,packet_db[cmd].pos[0]);
+ action_type = RFIFOB(fd,packet_db[cmd].pos[1]);
+
+ switch(action_type) {
+ case 0x00: // once attack
+ case 0x07: // continuous attack
+ if(sd->sc_data[SC_WEDDING].timer != -1 || sd->view_class==22)
+ return;
+ if (sd->vender_id != 0)
+ return;
+ if (!battle_config.sdelay_attack_enable && pc_checkskill(sd, SA_FREECAST) <= 0) {
+ if (DIFF_TICK(tick, sd->canact_tick) < 0) {
+ clif_skill_fail(sd, 1, 4, 0);
+ return;
+ }
+ }
+ if (sd->invincible_timer != -1)
+ pc_delinvincibletimer(sd);
+ if (sd->attacktarget > 0) // [Valaris]
+ sd->attacktarget = 0;
+ pc_attack(sd, target_id, action_type != 0);
+ break;
+ case 0x02: // sitdown
+ if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, NV_BASIC) >= 3) {
+ pc_stop_walking(sd, 1);
+ skill_gangsterparadise(sd, 1); // ギャングスターパラダイス設定
+ pc_setsit(sd);
+ clif_sitting(fd, sd);
+ } else
+ clif_skill_fail(sd, 1, 0, 2);
+ break;
+ case 0x03: // standup
+ skill_gangsterparadise(sd, 0); // ギャングスターパラダイス解除
+ pc_setstand(sd);
+ WBUFW(buf, 0) = 0x8a;
+ WBUFL(buf, 2) = sd->bl.id;
+ WBUFB(buf,26) = 3;
+ clif_send(buf, packet_db[0x8a].len, &sd->bl, AREA);
+ break;
+ }
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_Restart(int fd, struct map_session_data *sd, int cmd) {
+ int restarttype=RFIFOB(fd,packet_db[cmd].pos[0]);
+
+ nullpo_retv(sd);
+
+ switch(restarttype){
+ case 0x00:
+ if (pc_isdead(sd)) {
+ pc_setstand(sd);
+ pc_setrestartvalue(sd, 3);
+ pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, 2);
+ }
+ break;
+ case 0x01:
+ if(!pc_isdead(sd) && (sd->opt1 || (sd->opt2 && !(night_flag == 1 && sd->opt2 == STATE_BLIND))))
+ return;
+
+ /* Rovert's Prevent logout option - Fixed [Valaris] */
+ if ((battle_config.prevent_logout && (gettick() - sd->canlog_tick) >= 10000) || (!battle_config.prevent_logout)) {
+ chrif_charselectreq(sd);
+ } else {
+ WFIFOW(fd,0)=0x18b;
+ WFIFOW(fd,2)=1;
+
+ WFIFOSET(fd,packet_db[0x018b].len);
+ }
+ break;
+ }
+}
+
+/*==========================================
+ * Transmission of a wisp (S 0096 <len>.w <nick>.24B <message>.?B)
+ *------------------------------------------
+ */
+void clif_parse_Wis(int fd, struct map_session_data *sd, int cmd) { // S 0096 <len>.w <nick>.24B <message>.?B // rewritten by [Yor]
+ int len=RFIFOW(fd,packet_db[cmd].pos[0]);
+
+ if( sd && sd->sc_data &&
+ (sd->sc_data[SC_BERSERK].timer!=-1 || //バーサーク時は会話も不可
+ sd->sc_data[SC_NOCHAT].timer!=-1 ) ) //チャット禁止
+ return;
+
+ intif_wis_message(sd,RFIFOP(fd,packet_db[cmd].pos[1]),RFIFOP(fd,packet_db[cmd].pos[2]),len-packet_db[cmd].pos[2]);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_GMmessage(int fd, struct map_session_data *sd, int cmd) {
+// /b
+ int len;
+ nullpo_retv(sd);
+
+ len=RFIFOW(fd,packet_db[cmd].pos[0]);
+ if (battle_config.atc_gmonly == 0 ||
+ pc_isGM(sd) >= get_atcommand_level(AtCommand_Broadcast))
+ intif_GMmessage(RFIFOP(fd,packet_db[cmd].pos[1]),len-packet_db[cmd].pos[1],0);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_TakeItem(int fd, struct map_session_data *sd, int cmd) {
+ struct flooritem_data *fitem;
+ int map_object_id;
+
+ nullpo_retv(sd);
+
+ map_object_id = RFIFOL(fd,packet_db[cmd].pos[0]);
+ fitem = (struct flooritem_data*)map_id2bl(map_object_id);
+
+ if (pc_isdead(sd)) {
+ clif_clearchar_area(&sd->bl, 1);
+ return;
+ }
+
+ if( sd->npc_id!=0 || sd->vender_id != 0 || sd->opt1 > 0 ||
+ (sd->sc_data && (sd->sc_data[SC_TRICKDEAD].timer != -1 || //死んだふり
+ sd->sc_data[SC_BLADESTOP].timer != -1 || //白刃取り
+ sd->sc_data[SC_BERSERK].timer!=-1 || //バーサーク
+ sd->sc_data[SC_NOCHAT].timer!=-1 )) ) //会話禁止
+ return;
+
+ if (fitem == NULL || fitem->bl.m != sd->bl.m)
+ return;
+
+ pc_takeitem(sd, fitem);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_DropItem(int fd, struct map_session_data *sd, int cmd) {
+ int item_index, item_amount;
+
+ nullpo_retv(sd);
+
+ if (pc_isdead(sd)) {
+ clif_clearchar_area(&sd->bl, 1);
+ return;
+ }
+ if (sd->npc_id != 0 || sd->vender_id != 0 || sd->opt1 > 0 ||
+ (sd->sc_data && (sd->sc_data[SC_AUTOCOUNTER].timer != -1 || //オートカウンター
+ sd->sc_data[SC_BLADESTOP].timer != -1 || //白刃取り
+ sd->sc_data[SC_BERSERK].timer != -1)) ) //バーサーク
+ return;
+
+ item_index = RFIFOW(fd,packet_db[cmd].pos[0])-2;
+ item_amount = RFIFOW(fd,packet_db[cmd].pos[1]);
+
+ pc_dropitem(sd, item_index, item_amount);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_UseItem(int fd, struct map_session_data *sd, int cmd) {
+ nullpo_retv(sd);
+
+ if (pc_isdead(sd)) {
+ clif_clearchar_area(&sd->bl, 1);
+ return;
+ }
+ if (sd->npc_id!=0 || sd->vender_id != 0 || sd->opt1 > 0 ||
+ (sd->sc_data && (sd->sc_data[SC_TRICKDEAD].timer != -1 || //死んだふり
+ sd->sc_data[SC_BLADESTOP].timer != -1 || //白刃取り
+ sd->sc_data[SC_BERSERK].timer!=-1 || //バーサーク
+ sd->sc_data[SC_NOCHAT].timer!=-1 )) ) //会話禁止
+ return;
+
+
+ if (sd->invincible_timer != -1)
+ pc_delinvincibletimer(sd);
+
+ pc_useitem(sd,RFIFOW(fd,packet_db[cmd].pos[0])-2);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_EquipItem(int fd,struct map_session_data *sd, int cmd)
+{
+ int index;
+
+ nullpo_retv(sd);
+
+ if(pc_isdead(sd)) {
+ clif_clearchar_area(&sd->bl,1);
+ return;
+ }
+ index = RFIFOW(fd,packet_db[cmd].pos[0])-2;
+ if(sd->npc_id!=0 || sd->vender_id != 0) return;
+ if(sd->sc_data && ( sd->sc_data[SC_BLADESTOP].timer!=-1 || sd->sc_data[SC_BERSERK].timer!=-1 )) return;
+
+ if(sd->status.inventory[index].identify != 1) { // 未鑑定
+ clif_equipitemack(sd,index,0,0); // fail
+ return;
+ }
+ //ペット用装備であるかないか
+ if(sd->inventory_data[index]) {
+ if(sd->inventory_data[index]->type != 8){
+ if(sd->inventory_data[index]->type == 10)
+ RFIFOW(fd,packet_db[cmd].pos[1])=0x8000; // 矢を無理やり装備できるように(−−;
+ pc_equipitem(sd,index,RFIFOW(fd,packet_db[cmd].pos[1]));
+ } else
+ pet_equipitem(sd,index);
+ }
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_UnequipItem(int fd,struct map_session_data *sd, int cmd)
+{
+ int index;
+
+ nullpo_retv(sd);
+
+ if(pc_isdead(sd)) {
+ clif_clearchar_area(&sd->bl,1);
+ return;
+ }
+
+ index = packet_db[cmd].pos[0]-2;
+ if(sd->status.inventory[index].attribute == 1 && sd->sc_data && sd->sc_data[SC_BROKNWEAPON].timer!=-1)
+ skill_status_change_end(&sd->bl,SC_BROKNWEAPON,-1);
+ if(sd->status.inventory[index].attribute == 1 && sd->sc_data && sd->sc_data[SC_BROKNARMOR].timer!=-1)
+ skill_status_change_end(&sd->bl,SC_BROKNARMOR,-1);
+ if(sd->sc_data && ( sd->sc_data[SC_BLADESTOP].timer!=-1 || sd->sc_data[SC_BERSERK].timer!=-1 ))
+ return;
+
+ if(sd->npc_id!=0 || sd->vender_id != 0 || sd->opt1 > 0) return;
+ pc_unequipitem(sd,RFIFOW(fd,packet_db[cmd].pos[0])-2,0);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_NpcClicked(int fd,struct map_session_data *sd, int cmd)
+{
+ nullpo_retv(sd);
+
+ if(pc_isdead(sd)) {
+ clif_clearchar_area(&sd->bl,1);
+ return;
+ }
+ if(sd->npc_id!=0 || sd->vender_id != 0)
+ return;
+ npc_click(sd,RFIFOL(fd,packet_db[cmd].pos[0]));
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_NpcBuySellSelected(int fd,struct map_session_data *sd, int cmd)
+{
+ npc_buysellsel(sd,RFIFOL(fd,packet_db[cmd].pos[0]),RFIFOB(fd,packet_db[cmd].pos[1]));
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_NpcBuyListSend(int fd,struct map_session_data *sd, int cmd)
+{
+ int fail=0,n;
+ unsigned short *item_list;
+
+ n = (RFIFOW(fd,packet_db[cmd].pos[0])-4) /4;
+ item_list = (unsigned short*)RFIFOP(fd,packet_db[cmd].pos[1]);
+
+ fail = npc_buylist(sd,n,item_list);
+
+ WFIFOW(fd,0)=0xca;
+ WFIFOB(fd,2)=fail;
+ WFIFOSET(fd,packet_db[0xca].len);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_NpcSellListSend(int fd,struct map_session_data *sd, int cmd)
+{
+ int fail=0,n;
+ unsigned short *item_list;
+
+ n = (RFIFOW(fd,packet_db[cmd].pos[0])-4) /4;
+ item_list = (unsigned short*)RFIFOP(fd,packet_db[cmd].pos[1]);
+
+ fail = npc_selllist(sd,n,item_list);
+
+ WFIFOW(fd,0)=0xcb;
+ WFIFOB(fd,2)=fail;
+ WFIFOSET(fd,packet_db[0xcb].len);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_CreateChatRoom(int fd,struct map_session_data *sd, int cmd)
+{
+ if(battle_config.basic_skill_check == 0 || pc_checkskill(sd,NV_BASIC) >= 4){
+ int len = RFIFOW(fd,packet_db[cmd].pos[0]);
+ chat_createchat(sd,RFIFOW(fd,packet_db[cmd].pos[1]),RFIFOB(fd,packet_db[cmd].pos[2]),RFIFOP(fd,packet_db[cmd].pos[3]),RFIFOP(fd,packet_db[cmd].pos[4]),len-packet_db[cmd].pos[4]);
+ }
+ else
+ clif_skill_fail(sd,1,0,3);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_ChatAddMember(int fd,struct map_session_data *sd, int cmd)
+{
+ chat_joinchat(sd,RFIFOL(fd,packet_db[cmd].pos[0]),RFIFOP(fd,packet_db[cmd].pos[1]));
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_ChatRoomStatusChange(int fd,struct map_session_data *sd, int cmd)
+{
+ int len = RFIFOW(fd,packet_db[cmd].pos[0]);
+ chat_changechatstatus(sd,RFIFOW(fd,packet_db[cmd].pos[1]),RFIFOB(fd,packet_db[cmd].pos[2]),RFIFOP(fd,packet_db[cmd].pos[3]),RFIFOP(fd,packet_db[cmd].pos[4]),len-packet_db[cmd].pos[4]);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_ChangeChatOwner(int fd,struct map_session_data *sd, int cmd)
+{
+ chat_changechatowner(sd,RFIFOP(fd,packet_db[cmd].pos[0]));
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_KickFromChat(int fd,struct map_session_data *sd, int cmd)
+{
+ chat_kickchat(sd,RFIFOP(fd,packet_db[cmd].pos[0]));
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_ChatLeave(int fd,struct map_session_data *sd, int cmd)
+{
+ chat_leavechat(sd);
+}
+
+/*==========================================
+ * 取引要請を相手に送る
+ *------------------------------------------
+ */
+void clif_parse_TradeRequest(int fd,struct map_session_data *sd, int cmd)
+{
+ nullpo_retv(sd);
+
+ if(battle_config.basic_skill_check == 0 || pc_checkskill(sd,NV_BASIC) >= 1){
+ trade_traderequest(sd,RFIFOL(sd->fd,packet_db[cmd].pos[0]));
+ }
+ else
+ clif_skill_fail(sd,1,0,0);
+}
+
+/*==========================================
+ * 取引要請
+ *------------------------------------------
+ */
+void clif_parse_TradeAck(int fd,struct map_session_data *sd, int cmd)
+{
+ nullpo_retv(sd);
+
+ trade_tradeack(sd,RFIFOB(sd->fd,packet_db[cmd].pos[0]));
+}
+
+/*==========================================
+ * アイテム追加
+ *------------------------------------------
+ */
+void clif_parse_TradeAddItem(int fd,struct map_session_data *sd, int cmd)
+{
+ nullpo_retv(sd);
+
+ trade_tradeadditem(sd,RFIFOW(sd->fd,packet_db[cmd].pos[0]),RFIFOL(sd->fd,packet_db[cmd].pos[1]));
+}
+
+/*==========================================
+ * アイテム追加完了(ok押し)
+ *------------------------------------------
+ */
+void clif_parse_TradeOk(int fd,struct map_session_data *sd, int cmd)
+{
+ trade_tradeok(sd);
+}
+
+/*==========================================
+ * 取引キャンセル
+ *------------------------------------------
+ */
+void clif_parse_TradeCancel(int fd,struct map_session_data *sd, int cmd)
+{
+ trade_tradecancel(sd);
+}
+
+/*==========================================
+ * 取引許諾(trade押し)
+ *------------------------------------------
+ */
+void clif_parse_TradeCommit(int fd,struct map_session_data *sd, int cmd)
+{
+ trade_tradecommit(sd);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_StopAttack(int fd,struct map_session_data *sd, int cmd)
+{
+ pc_stopattack(sd);
+}
+
+/*==========================================
+ * カートへアイテムを移す
+ *------------------------------------------
+ */
+void clif_parse_PutItemToCart(int fd,struct map_session_data *sd, int cmd)
+{
+ nullpo_retv(sd);
+
+ if(sd->npc_id!=0 || sd->vender_id != 0)
+ return;
+ pc_putitemtocart(sd,RFIFOW(fd,packet_db[cmd].pos[0])-2,RFIFOL(fd,packet_db[cmd].pos[1]));
+}
+/*==========================================
+ * カートからアイテムを出す
+ *------------------------------------------
+ */
+void clif_parse_GetItemFromCart(int fd,struct map_session_data *sd, int cmd)
+{
+ nullpo_retv(sd);
+
+ if(sd->npc_id!=0 || sd->vender_id != 0) return;
+ pc_getitemfromcart(sd,RFIFOW(fd,packet_db[cmd].pos[0])-2,RFIFOL(fd,packet_db[cmd].pos[1]));
+}
+
+/*==========================================
+ * 付属品(鷹,ペコ,カート)をはずす
+ *------------------------------------------
+ */
+void clif_parse_RemoveOption(int fd,struct map_session_data *sd, int cmd)
+{
+ if(pc_isriding(sd)) { // jobchange when removing peco [Valaris]
+ if(sd->status.class==13)
+ sd->status.class=sd->view_class=7;
+
+ if(sd->status.class==21)
+ sd->status.class=sd->view_class=14;
+
+ if(sd->status.class==4014)
+ sd->status.class=sd->view_class=4008;
+
+ if(sd->status.class==4022)
+ sd->status.class=sd->view_class=4015;
+ }
+
+ pc_setoption(sd,0);
+}
+
+/*==========================================
+ * チェンジカート
+ *------------------------------------------
+ */
+void clif_parse_ChangeCart(int fd,struct map_session_data *sd, int cmd)
+{
+ pc_setcart(sd,RFIFOW(fd,packet_db[cmd].pos[0]));
+}
+
+/*==========================================
+ * ステータスアップ
+ *------------------------------------------
+ */
+void clif_parse_StatusUp(int fd,struct map_session_data *sd, int cmd)
+{
+ pc_statusup(sd,RFIFOW(fd,packet_db[cmd].pos[0]));
+}
+
+/*==========================================
+ * スキルレベルアップ
+ *------------------------------------------
+ */
+void clif_parse_SkillUp(int fd,struct map_session_data *sd, int cmd)
+{
+ pc_skillup(sd,RFIFOW(fd,packet_db[cmd].pos[0]));
+}
+
+/*==========================================
+ * スキル使用(ID指定)
+ *------------------------------------------
+ */
+void clif_parse_UseSkillToId(int fd, struct map_session_data *sd, int cmd) {
+ int skillnum, skilllv,lv, target_id;
+ unsigned int tick=gettick();
+
+ nullpo_retv(sd);
+
+ if (sd->chatID || sd->npc_id != 0 || sd->vender_id != 0)
+ return;
+
+ skilllv = RFIFOW(fd,packet_db[cmd].pos[0]);
+ skillnum = RFIFOW(fd,packet_db[cmd].pos[1]);
+ target_id = RFIFOL(fd,packet_db[cmd].pos[2]);
+
+ if(skillnotok(skillnum, sd))
+ return;
+
+ if (sd->skilltimer != -1) {
+ if (skillnum != SA_CASTCANCEL)
+ return;
+ } else if (DIFF_TICK(tick, sd->canact_tick) < 0) {
+ clif_skill_fail(sd, skillnum, 4, 0);
+ return;
+ }
+
+ if ((sd->sc_data[SC_TRICKDEAD].timer != -1 && skillnum != NV_TRICKDEAD) ||
+ sd->sc_data[SC_BERSERK].timer != -1 || sd->sc_data[SC_NOCHAT].timer!=-1 ||
+ sd->sc_data[SC_WEDDING].timer!=-1 || sd->view_class==22)
+ return;
+ if (sd->invincible_timer != -1)
+ pc_delinvincibletimer(sd);
+ if (sd->skillitem >= 0 && sd->skillitem == skillnum) {
+ if (skilllv != sd->skillitemlv)
+ skilllv = sd->skillitemlv;
+ skill_use_id(sd, target_id, skillnum, skilllv);
+ } else {
+ sd->skillitem = sd->skillitemlv = -1;
+ if (skillnum == MO_EXTREMITYFIST) {
+ if ((sd->sc_data[SC_COMBO].timer == -1 || (sd->sc_data[SC_COMBO].val1 != MO_COMBOFINISH && sd->sc_data[SC_COMBO].val1 != CH_CHAINCRUSH))) {
+ if (!sd->state.skill_flag ) {
+ sd->state.skill_flag = 1;
+ clif_skillinfo(sd, MO_EXTREMITYFIST, 1, -1);
+ return;
+ } else if (sd->bl.id == target_id) {
+ clif_skillinfo(sd, MO_EXTREMITYFIST, 1, -1);
+ return;
+ }
+ }
+ }
+ if ((lv = pc_checkskill(sd, skillnum)) > 0) {
+ if (skilllv > lv)
+ skilllv = lv;
+ skill_use_id(sd, target_id, skillnum, skilllv);
+ if (sd->state.skill_flag)
+ sd->state.skill_flag = 0;
+ }
+ }
+}
+
+/*==========================================
+ * スキル使用(場所指定)
+ *------------------------------------------
+ */
+void clif_parse_UseSkillToPos(int fd, struct map_session_data *sd, int cmd) {
+ int skillnum, skilllv, lv, x, y;
+ unsigned int tick = gettick();
+
+ nullpo_retv(sd);
+
+ if (sd->npc_id != 0 || sd->vender_id != 0) return;
+ if(sd->chatID) return;
+
+ skilllv = RFIFOW(fd,packet_db[cmd].pos[0]);
+ skillnum = RFIFOW(fd,packet_db[cmd].pos[1]);
+ x = RFIFOW(fd,packet_db[cmd].pos[2]);
+ y = RFIFOW(fd,packet_db[cmd].pos[3]);
+
+ if(packet_db[cmd].pos[4]){
+ if(pc_issit(sd)){
+ clif_skill_fail(sd,skillnum,0,0);
+ return;
+ }
+ memcpy(sd->message,RFIFOP(fd,packet_db[cmd].pos[4]),80);
+ }
+
+ if (sd->skilltimer != -1)
+ return;
+ else if (DIFF_TICK(tick, sd->canact_tick) < 0) {
+ clif_skill_fail(sd, skillnum, 4, 0);
+ return;
+ }
+
+ if((sd->sc_data[SC_TRICKDEAD].timer != -1 && skillnum != NV_TRICKDEAD) ||
+ sd->sc_data[SC_BERSERK].timer!=-1 || sd->sc_data[SC_NOCHAT].timer!=-1 ||
+ sd->sc_data[SC_WEDDING].timer!=-1 || sd->view_class==22)
+ return;
+ if (sd->invincible_timer != -1)
+ pc_delinvincibletimer(sd);
+ if (sd->skillitem >= 0 && sd->skillitem == skillnum) {
+ if (skilllv != sd->skillitemlv)
+ skilllv = sd->skillitemlv;
+ skill_use_pos(sd, x, y, skillnum, skilllv);
+ } else {
+ sd->skillitem = sd->skillitemlv = -1;
+ if ((lv = pc_checkskill(sd, skillnum)) > 0) {
+ if (skilllv > lv)
+ skilllv = lv;
+ skill_use_pos(sd, x, y, skillnum,skilllv);
+ }
+ }
+}
+
+/*==========================================
+ * スキル使用(map指定)
+ *------------------------------------------
+ */
+void clif_parse_UseSkillMap(int fd,struct map_session_data *sd, int cmd)
+{
+ nullpo_retv(sd);
+
+ if(sd->chatID) return;
+
+ if(sd->npc_id!=0 || sd->vender_id != 0 || (sd->sc_data &&
+ (sd->sc_data[SC_TRICKDEAD].timer != -1 ||
+ sd->sc_data[SC_BERSERK].timer!=-1 ||
+ sd->sc_data[SC_NOCHAT].timer!=-1 ||
+ sd->sc_data[SC_WEDDING].timer!=-1 ||
+ sd->view_class==22)))
+ return;
+
+ if(sd->invincible_timer != -1)
+ pc_delinvincibletimer(sd);
+
+ skill_castend_map(sd,RFIFOW(fd,packet_db[cmd].pos[0]),RFIFOP(fd,packet_db[cmd].pos[1]));
+}
+/*==========================================
+ * メモ要求
+ *------------------------------------------
+ */
+void clif_parse_RequestMemo(int fd,struct map_session_data *sd, int cmd)
+{
+ pc_memo(sd,-1);
+}
+/*==========================================
+ * アイテム合成
+ *------------------------------------------
+ */
+void clif_parse_ProduceMix(int fd,struct map_session_data *sd, int cmd)
+{
+ nullpo_retv(sd);
+
+ sd->state.produce_flag = 0;
+ skill_produce_mix(sd,RFIFOW(fd,packet_db[cmd].pos[0]),RFIFOW(fd,packet_db[cmd].pos[1]),RFIFOW(fd,packet_db[cmd].pos[2]),RFIFOW(fd,packet_db[cmd].pos[3]));
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_NpcSelectMenu(int fd,struct map_session_data *sd, int cmd)
+{
+ nullpo_retv(sd);
+
+ sd->npc_menu=RFIFOB(fd,packet_db[cmd].pos[1]);
+ npc_scriptcont(sd,RFIFOL(fd,packet_db[cmd].pos[0]));
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_NpcNextClicked(int fd,struct map_session_data *sd, int cmd)
+{
+ npc_scriptcont(sd,RFIFOL(fd,packet_db[cmd].pos[0]));
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_NpcAmountInput(int fd,struct map_session_data *sd, int cmd)
+{
+ nullpo_retv(sd);
+
+#define RFIFOL_(fd,pos) (*(int*)(session[fd]->rdata+session[fd]->rdata_pos+(pos)))
+ //Input Value overflow Exploit FIX
+ sd->npc_amount=RFIFOL(fd,packet_db[cmd].pos[1]); //fixed by Lupus. npc_amount is (int) but was RFIFOL changing it to (unsigned int)
+#undef RFIFOL_
+
+ npc_scriptcont(sd,RFIFOL(fd,packet_db[cmd].pos[0]));
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_NpcStringInput(int fd,struct map_session_data *sd, int cmd)
+{
+ int len = RFIFOW(fd,packet_db[cmd].pos[0]);
+
+ nullpo_retv(sd);
+
+ if(len-packet_db[cmd].pos[2]+1 >= sizeof(sd->npc_str)){
+ printf("clif: input string too long !\n");
+ memcpy(sd->npc_str,RFIFOP(fd,packet_db[cmd].pos[2]),sizeof(sd->npc_str));
+ sd->npc_str[sizeof(sd->npc_str)-1]=0;
+ }else
+ strncpy(sd->npc_str,RFIFOP(fd,packet_db[cmd].pos[2]),256);
+ npc_scriptcont(sd,RFIFOL(fd,packet_db[cmd].pos[1]));
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_parse_NpcCloseClicked(int fd,struct map_session_data *sd, int cmd)
+{
+ npc_scriptcont(sd,RFIFOL(fd,packet_db[cmd].pos[0]));
+}
+
+/*==========================================
+ * アイテム鑑定
+ *------------------------------------------
+ */
+void clif_parse_ItemIdentify(int fd,struct map_session_data *sd, int cmd)
+{
+ pc_item_identify(sd,RFIFOW(fd,packet_db[cmd].pos[0])-2);
+}
+/*==========================================
+ * 矢作成
+ *------------------------------------------
+ */
+void clif_parse_SelectArrow(int fd,struct map_session_data *sd, int cmd)
+{
+ nullpo_retv(sd);
+
+ sd->state.make_arrow_flag = 0;
+ skill_arrow_create(sd,RFIFOW(fd,packet_db[cmd].pos[0]));
+}
+/*==========================================
+ * オートスペル受信
+ *------------------------------------------
+ */
+void clif_parse_AutoSpell(int fd,struct map_session_data *sd, int cmd)
+{
+ skill_autospell(sd,RFIFOW(fd,packet_db[cmd].pos[0]));
+}
+/*==========================================
+ * カード使用
+ *------------------------------------------
+ */
+void clif_parse_UseCard(int fd,struct map_session_data *sd, int cmd)
+{
+ clif_use_card(sd,RFIFOW(fd,packet_db[cmd].pos[0])-2);
+}
+/*==========================================
+ * カード挿入装備選択
+ *------------------------------------------
+ */
+void clif_parse_InsertCard(int fd,struct map_session_data *sd, int cmd)
+{
+ pc_insert_card(sd,RFIFOW(fd,packet_db[cmd].pos[0])-2,RFIFOW(fd,packet_db[cmd].pos[1])-2);
+}
+
+/*==========================================
+ * 0193 キャラID名前引き
+ *------------------------------------------
+ */
+void clif_parse_SolveCharName(int fd,struct map_session_data *sd, int cmd)
+{
+ int char_id;
+
+ char_id = RFIFOL(fd,packet_db[cmd].pos[0]);
+ clif_solved_charname(sd,char_id);
+}
+
+/*==========================================
+ * 0197 /resetskill /resetstate
+ *------------------------------------------
+ */
+void clif_parse_ResetChar(int fd, struct map_session_data *sd, int cmd) {
+ nullpo_retv(sd);
+
+ if (battle_config.atc_gmonly == 0 || pc_isGM(sd) >= get_atcommand_level(AtCommand_ResetState)) {
+ switch(RFIFOW(fd,packet_db[cmd].pos[0])){
+ case 0:
+ pc_resetstate(sd);
+ break;
+ case 1:
+ pc_resetskill(sd);
+ break;
+ }
+ }
+}
+
+/*==========================================
+ * 019c /lb等
+ *------------------------------------------
+ */
+void clif_parse_LGMmessage(int fd, struct map_session_data *sd, int cmd) {
+ int len = RFIFOW(fd,packet_db[cmd].pos[0]);
+ unsigned char buf[64];
+
+ nullpo_retv(sd);
+
+ if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) &&
+ (pc_isGM(sd) >= get_atcommand_level(AtCommand_LocalBroadcast))) {
+ WBUFW(buf,0) = 0x9a;
+ WBUFW(buf,2) = len;
+ memcpy(WBUFP(buf,4), RFIFOP(fd,packet_db[cmd].pos[1]), len-packet_db[cmd].pos[1]);
+ clif_send(buf, len, &sd->bl, ALL_SAMEMAP);
+ }
+}
+
+/*==========================================
+ * カプラ倉庫へ入れる
+ *------------------------------------------
+ */
+void clif_parse_MoveToKafra(int fd, struct map_session_data *sd, int cmd) {
+ int item_index, item_amount;
+
+ nullpo_retv(sd);
+
+ if (sd->npc_id != 0 || sd->vender_id != 0)
+ return;
+ item_index = RFIFOW(fd,packet_db[cmd].pos[0])-2;
+ item_amount = RFIFOL(fd,packet_db[cmd].pos[1]);
+
+ if (sd->state.storage_flag)
+ storage_guild_storageadd(sd, item_index, item_amount);
+ else
+ storage_storageadd(sd, item_index, item_amount);
+}
+
+/*==========================================
+ * カプラ倉庫から出す
+ *------------------------------------------
+ */
+void clif_parse_MoveFromKafra(int fd,struct map_session_data *sd, int cmd) {
+ int item_index,item_amount;
+
+ nullpo_retv(sd);
+
+ if(sd->npc_id!=0 || sd->vender_id != 0) return;
+ item_index = RFIFOW(fd,packet_db[cmd].pos[0])-1;
+ item_amount = RFIFOL(fd,packet_db[cmd].pos[1]);
+
+ if(sd->state.storage_flag)
+ storage_guild_storageget(sd,item_index,item_amount);
+ else
+ storage_storageget(sd,item_index,item_amount);
+}
+
+/*==========================================
+ * カプラ倉庫へカートから入れる
+ *------------------------------------------
+ */
+void clif_parse_MoveToKafraFromCart(int fd, struct map_session_data *sd, int cmd) {
+ nullpo_retv(sd);
+
+ if (sd->npc_id != 0 || sd->vender_id != 0 || sd->trade_partner != 0) return;
+
+ if(sd->state.storage_flag)
+ storage_guild_storageaddfromcart(sd,RFIFOW(fd,packet_db[cmd].pos[0])-2,RFIFOL(fd,packet_db[cmd].pos[1]));
+ else
+ storage_storageaddfromcart(sd,RFIFOW(fd,packet_db[cmd].pos[0])-2,RFIFOL(fd,packet_db[cmd].pos[1]));
+}
+
+/*==========================================
+ * カプラ倉庫から出す
+ *------------------------------------------
+ */
+void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd, int cmd) {
+ nullpo_retv(sd);
+
+ if(sd->npc_id!=0 || sd->vender_id != 0) return;
+ if(sd->state.storage_flag)
+ storage_guild_storagegettocart(sd,RFIFOW(fd,packet_db[cmd].pos[0])-1,RFIFOL(fd,packet_db[cmd].pos[1]));
+ else
+ storage_storagegettocart(sd,RFIFOW(fd,packet_db[cmd].pos[0])-1,RFIFOL(fd,packet_db[cmd].pos[1]));
+}
+
+/*==========================================
+ * カプラ倉庫を閉じる
+ *------------------------------------------
+ */
+void clif_parse_CloseKafra(int fd, struct map_session_data *sd, int cmd) {
+ nullpo_retv(sd);
+
+ if (sd->state.storage_flag)
+ storage_guild_storageclose(sd);
+ else
+ storage_storageclose(sd);
+}
+
+/*==========================================
+ * パーティを作る
+ *------------------------------------------
+ */
+void clif_parse_CreateParty(int fd, struct map_session_data *sd, int cmd) {
+ if(battle_config.basic_skill_check == 0 || pc_checkskill(sd,NV_BASIC) >= 7){
+ party_create(sd,RFIFOP(fd,packet_db[cmd].pos[0]));
+ }
+ else
+ clif_skill_fail(sd,1,0,4);
+}
+
+/*==========================================
+ * パーティを作る
+ *------------------------------------------
+ */
+void clif_parse_CreateParty2(int fd,struct map_session_data *sd, int cmd)
+{
+ if(battle_config.basic_skill_check == 0 || pc_checkskill(sd,NV_BASIC) >= 7){
+ party_create(sd,RFIFOP(fd,packet_db[cmd].pos[0]));
+ }
+ else
+ clif_skill_fail(sd,1,0,4);
+}
+
+/*==========================================
+ * パーティに勧誘
+ *------------------------------------------
+ */
+void clif_parse_PartyInvite(int fd,struct map_session_data *sd, int cmd)
+{
+ party_invite(sd,RFIFOL(fd,packet_db[cmd].pos[0]));
+}
+/*==========================================
+ * パーティ勧誘返答
+ *------------------------------------------
+ */
+void clif_parse_ReplyPartyInvite(int fd,struct map_session_data *sd, int cmd)
+{
+ if(battle_config.basic_skill_check == 0 || pc_checkskill(sd,NV_BASIC) >= 5){
+ party_reply_invite(sd,RFIFOL(fd,packet_db[cmd].pos[0]),RFIFOL(fd,packet_db[cmd].pos[1]));
+ }
+ else {
+ party_reply_invite(sd,RFIFOL(fd,packet_db[cmd].pos[0]),-1);
+ clif_skill_fail(sd,1,0,4);
+ }
+}
+/*==========================================
+ * パーティ脱退要求
+ *------------------------------------------
+ */
+void clif_parse_LeaveParty(int fd,struct map_session_data *sd, int cmd)
+{
+ party_leave(sd);
+}
+/*==========================================
+ * パーティ除名要求
+ *------------------------------------------
+ */
+void clif_parse_RemovePartyMember(int fd,struct map_session_data *sd, int cmd)
+{
+ party_removemember(sd,RFIFOL(fd,packet_db[cmd].pos[0]),RFIFOP(fd,packet_db[cmd].pos[1]));
+}
+/*==========================================
+ * パーティ設定変更要求
+ *------------------------------------------
+ */
+void clif_parse_PartyChangeOption(int fd,struct map_session_data *sd, int cmd)
+{
+ party_changeoption(sd,RFIFOW(fd,packet_db[cmd].pos[0]),RFIFOW(fd,packet_db[cmd].pos[1]));
+}
+/*==========================================
+ * パーティメッセージ送信要求
+ *------------------------------------------
+ */
+void clif_parse_PartyMessage(int fd, struct map_session_data *sd, int cmd) {
+ nullpo_retv(sd);
+
+ if (is_atcommand(fd, sd, RFIFOP(fd, packet_db[cmd].pos[1]),0) != AtCommand_None)
+ return;
+ if(sd->sc_data &&
+ (sd->sc_data[SC_BERSERK].timer!=-1 || //バーサーク時は会話も不可
+ sd->sc_data[SC_NOCHAT].timer!=-1)) //チャット禁止
+ return;
+
+ party_send_message(sd,RFIFOP(fd,packet_db[cmd].pos[1]),RFIFOW(fd,packet_db[cmd].pos[0])-packet_db[cmd].pos[1]);
+}
+
+/*==========================================
+ * 露店閉鎖
+ *------------------------------------------
+ */
+void clif_parse_CloseVending(int fd,struct map_session_data *sd, int cmd)
+{
+ vending_closevending(sd);
+}
+
+/*==========================================
+ * 露店アイテムリスト要求
+ *------------------------------------------
+ */
+void clif_parse_VendingListReq(int fd,struct map_session_data *sd, int cmd)
+{
+ nullpo_retv(sd);
+
+ vending_vendinglistreq(sd,RFIFOL(fd,packet_db[cmd].pos[0]));
+ if(sd->npc_id)
+ npc_event_dequeue(sd);
+}
+
+/*==========================================
+ * 露店アイテム購入
+ *------------------------------------------
+ */
+void clif_parse_PurchaseReq(int fd,struct map_session_data *sd, int cmd)
+{
+ vending_purchasereq(sd,RFIFOW(fd,packet_db[cmd].pos[0]),RFIFOL(fd,packet_db[cmd].pos[1]),RFIFOP(fd,packet_db[cmd].pos[2]));
+}
+
+/*==========================================
+ * 露店開設
+ *------------------------------------------
+ */
+void clif_parse_OpenVending(int fd,struct map_session_data *sd, int cmd)
+{
+ vending_openvending(sd,RFIFOW(fd,packet_db[cmd].pos[0]),RFIFOP(fd,packet_db[cmd].pos[1]),RFIFOB(fd,packet_db[cmd].pos[2]),RFIFOP(fd,packet_db[cmd].pos[3]));
+}
+
+/*==========================================
+ * ギルドを作る
+ *------------------------------------------
+ */
+void clif_parse_CreateGuild(int fd,struct map_session_data *sd, int cmd)
+{
+ guild_create(sd,RFIFOP(fd,packet_db[cmd].pos[0]));
+}
+/*==========================================
+ * ギルドマスターかどうか確認
+ *------------------------------------------
+ */
+void clif_parse_GuildCheckMaster(int fd,struct map_session_data *sd, int cmd)
+{
+ clif_guild_masterormember(sd);
+}
+/*==========================================
+ * ギルド情報要求
+ *------------------------------------------
+ */
+void clif_parse_GuildRequestInfo(int fd,struct map_session_data *sd, int cmd)
+{
+ switch(RFIFOL(fd,packet_db[cmd].pos[0])){
+ case 0: // ギルド基本情報、同盟敵対情報
+ clif_guild_basicinfo(sd);
+ clif_guild_allianceinfo(sd);
+ break;
+ case 1: // メンバーリスト、役職名リスト
+ clif_guild_positionnamelist(sd);
+ clif_guild_memberlist(sd);
+ break;
+ case 2: // 役職名リスト、役職情報リスト
+ clif_guild_positionnamelist(sd);
+ clif_guild_positioninfolist(sd);
+ break;
+ case 3: // スキルリスト
+ clif_guild_skillinfo(sd);
+ break;
+ case 4: // 追放リスト
+ clif_guild_explusionlist(sd);
+ break;
+ default:
+ if(battle_config.error_log)
+ printf("clif: guild request info: unknown type %d\n",RFIFOL(fd,packet_db[cmd].pos[0]));
+ break;
+ }
+}
+/*==========================================
+ * ギルド役職変更
+ *------------------------------------------
+ */
+void clif_parse_GuildChangePositionInfo(int fd,struct map_session_data *sd, int cmd)
+{
+ int i;
+ for(i=4;i<RFIFOW(fd,packet_db[cmd].pos[0]);i+=40){
+ guild_change_position(sd,RFIFOL(fd,i),
+ RFIFOL(fd,i+4),RFIFOL(fd,i+12),RFIFOP(fd,i+16));
+ }
+}
+/*==========================================
+ * ギルドメンバ役職変更
+ *------------------------------------------
+ */
+void clif_parse_GuildChangeMemberPosition(int fd,struct map_session_data *sd, int cmd)
+{
+ int i;
+
+ nullpo_retv(sd);
+
+ for(i=4;i<RFIFOW(fd,packet_db[cmd].pos[0]);i+=12){
+ guild_change_memberposition(sd->status.guild_id,
+ RFIFOL(fd,i),RFIFOL(fd,i+4),RFIFOL(fd,i+8));
+ }
+}
+
+/*==========================================
+ * ギルドエンブレム要求
+ *------------------------------------------
+ */
+void clif_parse_GuildRequestEmblem(int fd,struct map_session_data *sd, int cmd)
+{
+ struct guild *g=guild_search(RFIFOL(fd,packet_db[cmd].pos[0]));
+ if(g!=NULL)
+ clif_guild_emblem(sd,g);
+}
+
+/*==========================================
+ * ギルドエンブレム変更
+ *------------------------------------------
+ */
+void clif_parse_GuildChangeEmblem(int fd,struct map_session_data *sd, int cmd)
+{
+ guild_change_emblem(sd,RFIFOW(fd,packet_db[cmd].pos[0])-packet_db[cmd].pos[1],RFIFOP(fd,packet_db[cmd].pos[1]));
+}
+/*==========================================
+ * ギルド告知変更
+ *------------------------------------------
+ */
+void clif_parse_GuildChangeNotice(int fd,struct map_session_data *sd, int cmd)
+{
+ guild_change_notice(sd,RFIFOL(fd,packet_db[cmd].pos[0]),RFIFOP(fd,packet_db[cmd].pos[1]),RFIFOP(fd,packet_db[cmd].pos[2]));
+}
+
+/*==========================================
+ * ギルド勧誘
+ *------------------------------------------
+ */
+void clif_parse_GuildInvite(int fd,struct map_session_data *sd, int cmd)
+{
+ guild_invite(sd,RFIFOL(fd,packet_db[cmd].pos[0]));
+}
+/*==========================================
+ * ギルド勧誘返信
+ *------------------------------------------
+ */
+void clif_parse_GuildReplyInvite(int fd,struct map_session_data *sd, int cmd)
+{
+ guild_reply_invite(sd,RFIFOL(fd,packet_db[cmd].pos[0]),RFIFOB(fd,packet_db[cmd].pos[1]));
+}
+/*==========================================
+ * ギルド脱退
+ *------------------------------------------
+ */
+void clif_parse_GuildLeave(int fd,struct map_session_data *sd, int cmd)
+{
+ guild_leave(sd,RFIFOL(fd,packet_db[cmd].pos[0]),RFIFOL(fd,packet_db[cmd].pos[1]),RFIFOL(fd,packet_db[cmd].pos[2]),RFIFOP(fd,packet_db[cmd].pos[3]));
+}
+/*==========================================
+ * ギルド追放
+ *------------------------------------------
+ */
+void clif_parse_GuildExplusion(int fd,struct map_session_data *sd, int cmd)
+{
+ guild_explusion(sd,RFIFOL(fd,packet_db[cmd].pos[0]),RFIFOL(fd,packet_db[cmd].pos[1]),RFIFOL(fd,packet_db[cmd].pos[2]),RFIFOP(fd,packet_db[cmd].pos[3]));
+}
+
+/*==========================================
+ * ギルド会話
+ *------------------------------------------
+ */
+void clif_parse_GuildMessage(int fd,struct map_session_data *sd, int cmd) {
+ nullpo_retv(sd);
+
+ if (is_atcommand(fd, sd, RFIFOP(fd, packet_db[cmd].pos[1]), 0) != AtCommand_None)
+ return;
+ if(sd->sc_data &&
+ (sd->sc_data[SC_BERSERK].timer!=-1 || //バーサーク時は会話も不可
+ sd->sc_data[SC_NOCHAT].timer!=-1)) //チャット禁止
+ return;
+
+ guild_send_message(sd,RFIFOP(fd,packet_db[cmd].pos[1]),RFIFOW(fd,packet_db[cmd].pos[0])-packet_db[cmd].pos[1]);
+}
+
+/*==========================================
+ * ギルド同盟要求
+ *------------------------------------------
+ */
+void clif_parse_GuildRequestAlliance(int fd,struct map_session_data *sd, int cmd)
+{
+ guild_reqalliance(sd,RFIFOL(fd,packet_db[cmd].pos[0]));
+}
+/*==========================================
+ * ギルド同盟要求返信
+ *------------------------------------------
+ */
+void clif_parse_GuildReplyAlliance(int fd,struct map_session_data *sd, int cmd)
+{
+ guild_reply_reqalliance(sd,RFIFOL(fd,packet_db[cmd].pos[0]),RFIFOL(fd,packet_db[cmd].pos[1]));
+}
+/*==========================================
+ * ギルド関係解消
+ *------------------------------------------
+ */
+void clif_parse_GuildDelAlliance(int fd,struct map_session_data *sd, int cmd)
+{
+ guild_delalliance(sd,RFIFOL(fd,packet_db[cmd].pos[0]),RFIFOL(fd,packet_db[cmd].pos[1]));
+}
+/*==========================================
+ * ギルド敵対
+ *------------------------------------------
+ */
+void clif_parse_GuildOpposition(int fd,struct map_session_data *sd, int cmd)
+{
+ guild_opposition(sd,RFIFOL(fd,packet_db[cmd].pos[0]));
+}
+/*==========================================
+ * ギルド解散
+ *------------------------------------------
+ */
+void clif_parse_GuildBreak(int fd,struct map_session_data *sd, int cmd)
+{
+ guild_break(sd,RFIFOP(fd,packet_db[cmd].pos[0]));
+}
+
+// pet
+void clif_parse_PetMenu(int fd,struct map_session_data *sd, int cmd)
+{
+ pet_menu(sd,RFIFOB(fd,packet_db[cmd].pos[0]));
+}
+void clif_parse_CatchPet(int fd,struct map_session_data *sd, int cmd)
+{
+ pet_catch_process2(sd,RFIFOL(fd,packet_db[cmd].pos[0]));
+}
+
+void clif_parse_SelectEgg(int fd,struct map_session_data *sd, int cmd)
+{
+ pet_select_egg(sd,RFIFOW(fd,packet_db[cmd].pos[0])-2);
+}
+
+void clif_parse_SendEmotion(int fd,struct map_session_data *sd, int cmd)
+{
+ nullpo_retv(sd);
+
+ if(sd->pd)
+ clif_pet_emotion(sd->pd,RFIFOL(fd,packet_db[cmd].pos[0]));
+}
+
+void clif_parse_ChangePetName(int fd,struct map_session_data *sd, int cmd)
+{
+ pet_change_name(sd,RFIFOP(fd,packet_db[cmd].pos[0]));
+}
+
+// Kick (right click menu for GM "(name) force to quit")
+void clif_parse_GMKick(int fd, struct map_session_data *sd, int cmd) {
+ struct block_list *target;
+ int tid = RFIFOL(fd,packet_db[cmd].pos[0]);
+
+ nullpo_retv(sd);
+
+ if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) &&
+ (pc_isGM(sd) >= get_atcommand_level(AtCommand_Kick))) {
+ target = map_id2bl(tid);
+ if (target) {
+ if (target->type == BL_PC) {
+ struct map_session_data *tsd = (struct map_session_data *)target;
+ if (pc_isGM(sd) > pc_isGM(tsd))
+ clif_GM_kick(sd, tsd, 1);
+ else
+ clif_GM_kickack(sd, 0);
+ } else if (target->type == BL_MOB) {
+ struct mob_data *md = (struct mob_data *)target;
+ sd->state.attack_type = 0;
+ mob_damage(&sd->bl, md, md->hp, 2);
+ } else
+ clif_GM_kickack(sd, 0);
+ } else
+ clif_GM_kickack(sd, 0);
+ }
+}
+
+/*==========================================
+ * GM funtions
+ *------------------------------------------
+ */
+void clif_parse_GMHide(int fd,struct map_session_data *sd, int cmd) {
+ nullpo_retv(sd);
+
+ if(pc_isGM(sd) >= get_atcommand_level(AtCommand_Hide)) {
+ if(sd->status.option&0x40){
+ sd->status.option&=~0x40;
+ clif_displaymessage(fd,"invisible off!");
+ }else{
+ sd->status.option|=0x40;
+ clif_displaymessage(fd,"invisible!");
+ }
+ clif_changeoption(&sd->bl);
+ }
+}
+
+/*==========================================
+ * GMによるチャット禁止時間付与
+ *------------------------------------------
+ */
+void clif_parse_GMReqNoChat(int fd,struct map_session_data *sd, int cmd)
+{
+ int tid = RFIFOL(fd,packet_db[cmd].pos[0]);
+ int type = RFIFOB(fd,packet_db[cmd].pos[1]);
+ int limit = RFIFOW(fd,packet_db[cmd].pos[2]);
+ struct block_list *bl = map_id2bl(tid);
+ struct map_session_data *dstsd;
+ int dstfd;
+
+ nullpo_retv(sd);
+
+ if(!battle_config.muting_players) {
+ clif_displaymessage(fd, "Muting is disabled.");
+ return;
+ }
+
+ if(type == 0)
+ limit = 0 - limit;
+ if(bl->type == BL_PC && (dstsd =(struct map_session_data *)bl)){
+ if((tid == bl->id && type == 2 && !pc_isGM(sd)) || (pc_isGM(sd) > pc_isGM(dstsd)) ){
+ dstfd = dstsd->fd;
+ WFIFOW(dstfd,0)=0x14b;
+ WFIFOB(dstfd,2)=(type==2)?1:type;
+ memcpy(WFIFOP(dstfd,3),sd->status.name,24);
+ WFIFOSET(dstfd,packet_db[0x14b].len);
+ dstsd->status.manner -= limit;
+ if(dstsd->status.manner < 0)
+ skill_status_change_start(bl,SC_NOCHAT,0,0,0,0,0,0);
+ else{
+ dstsd->status.manner = 0;
+ skill_status_change_end(bl,SC_NOCHAT,-1);
+ }
+ printf("name:%s type:%d limit:%d manner:%d\n",dstsd->status.name,type,limit,dstsd->status.manner);
+ }
+ }
+
+ return;
+}
+/*==========================================
+ * GMによるチャット禁止時間参照(?)
+ *------------------------------------------
+ */
+void clif_parse_GMReqNoChatCount(int fd,struct map_session_data *sd, int cmd)
+{
+ int tid = RFIFOL(fd,packet_db[cmd].pos[0]);
+
+ WFIFOW(fd,0)=0x1e0;
+ WFIFOL(fd,2)=tid;
+ snprintf(WFIFOP(fd,6),24,"%d",tid);
+// memcpy(WFIFOP(fd,6),"TESTNAME",24);
+ WFIFOSET(fd,packet_db[0x1e0].len);
+
+ return;
+}
+
+int monk(struct map_session_data *sd, struct block_list *target, int type) {
+//R 01d1 <Monk id>L <Target monster id>L <Bool>L
+ int fd=sd->fd;
+ WFIFOW(fd,0)=0x1d1;
+ WFIFOL(fd,2)=sd->bl.id;
+ WFIFOL(fd,6)=target->id;
+ WFIFOL(fd,10)=type;
+ WFIFOSET(fd,packet_db[0x1d1].len);
+
+ return 0;
+}
+
+/*==========================================
+ * スパノビの/doridoriによるSPR2倍
+ *------------------------------------------
+ */
+void clif_parse_sn_doridori(int fd, struct map_session_data *sd, int cmd) {
+ if (sd)
+ sd->doridori_counter = 1;
+
+ return;
+}
+/*==========================================
+ * スパノビの爆裂波動
+ *------------------------------------------
+ */
+void clif_parse_sn_explosionspirits(int fd, struct map_session_data *sd, int cmd)
+{
+ if(sd){
+ int nextbaseexp=pc_nextbaseexp(sd);
+ struct pc_base_job s_class = pc_calc_base_job(sd->status.class);
+ if (battle_config.etc_log){
+ if(nextbaseexp != 0)
+ printf("SuperNovice explosionspirits!! %d %d %d %d\n",sd->bl.id,s_class.job,sd->status.base_exp,(int)((double)1000*sd->status.base_exp/nextbaseexp));
+ else
+ printf("SuperNovice explosionspirits!! %d %d %d 000\n",sd->bl.id,s_class.job,sd->status.base_exp);
+ }
+ if(s_class.job == 23 && sd->status.base_exp > 0 && nextbaseexp > 0 && (int)((double)1000*sd->status.base_exp/nextbaseexp)%100==0){
+ clif_skill_nodamage(&sd->bl,&sd->bl,MO_EXPLOSIONSPIRITS,5,1);
+ skill_status_change_start(&sd->bl,SkillStatusChangeTable[MO_EXPLOSIONSPIRITS],5,0,0,0,skill_get_time(MO_EXPLOSIONSPIRITS,5),0 );
+ }
+ }
+ return;
+}
+
+/*==========================================
+ * Friends List (davidsiaw)
+ *------------------------------------------
+ */
+void clif_friends_list_send(struct map_session_data *sd)
+{
+ unsigned char buf[1024];
+ int i,n=0;
+
+ // Packet name
+ WBUFW(buf,0)=0x201;
+
+ // check all 20 friends. stop at 0
+ for (i=0;i<20;i++)
+ {
+ if (!sd->status.friend_id[i])
+ break;
+
+ WBUFL(buf,4 + 32 * n + 1)=sd->status.friend_id[i];
+ //WBUFB(buf,4 + 32 * n + 5)=(online[n])?0:1; // <- We don't know this yet. I'd reckon its 5 but... i could be wrong.
+
+ memcpy(WBUFP(buf,4 + 32 * n + 8),&sd->status.friend_name[i],23);
+
+ n++;
+ }
+
+ WBUFW(buf,2) = 4 + 32 * n;
+
+ memcpy(WFIFOP(sd->fd,0), buf, sizeof(buf));
+ WFIFOSET(sd->fd,sizeof(buf));
+ //clif_send(buf,WBUFW(buf,2),&sd->bl,SELF);
+
+}
+void clif_parse_friends_list_add(int fd,struct map_session_data *sd)
+{
+ struct map_session_data *f_sd = map_nick2sd(RFIFOP(fd,2));
+
+ int i=0;
+
+ while (sd->status.friend_id[i]) { // Find an empty slot
+
+ if (sd->status.friend_id[i] == f_sd->status.char_id) {
+ clif_displaymessage(fd,"Friend already exists"); // Friend already exists
+ return;
+ }
+ i++;
+ if (i==20) {
+ clif_displaymessage(fd,"Friends list is full.");
+ return;
+ }
+
+ }
+
+ sd->status.friend_id[i] = f_sd->status.char_id;
+ memcpy(sd->status.friend_name[i],f_sd->status.name,23);
+ clif_displaymessage(fd,"Friend added.");
+
+ for (i=i+1; i<20; i++)
+ {
+ sd->status.friend_id[i] = 0;
+ }
+
+ clif_friends_list_send(sd);
+
+ //printf("clif_parse_friends_list_add");
+
+}
+void clif_parse_friends_list_remove(int fd,struct map_session_data *sd)
+{
+ // 0x203 </o> <ID to be removed W 4B>
+
+ int id = RFIFOL(fd,3);
+ char mes[80];
+
+ int i=0;
+
+
+ while (sd->status.friend_id[i] != id)
+ {
+ sprintf(mes, "Compare: %d and %d", id, sd->status.friend_id[i]);
+ clif_displaymessage(fd,mes);
+ i++;
+ if (i==20)
+ {
+ clif_displaymessage (fd,"Name not found in list");
+ clif_friends_list_send(sd);
+ return;
+ }
+ }
+
+ sd->status.friend_id[i] = 0;
+ memcpy(sd->status.friend_name[i],"",23);
+
+ // move all chars up
+
+ for (i=i+1; i<20; i++)
+ {
+ if(sd->status.friend_name[i])
+ {
+ sd->status.friend_id[i] = sd->status.friend_id[i-1];
+ memcpy(sd->status.friend_name[i],sd->status.friend_name[i-1],23);
+ }
+ else
+ {
+ sd->status.friend_id[i] = 0;
+ memcpy(sd->status.friend_name[i],"",23);
+ }
+
+ }
+
+ clif_friends_list_send(sd);
+
+}
+
+/*==========================================
+ * Whisper Ignoring [ /ex /in ]
+ *------------------------------------------
+ */
+int pstrcmp(const void *a, const void *b)
+{
+ return strcmp((char *)a, (char *)b);
+}
+void clif_parse_wisexin(int fd,struct map_session_data *sd, int cmd)
+{
+ int type = RFIFOB(fd,packet_db[cmd].pos[1]);
+ int i,flag=1;
+
+ if(sd){
+ qsort(sd->wis_refusal[0], MAX_WIS_REFUSAL, sizeof(sd->wis_refusal[0]), pstrcmp);
+ if(type==0){ //ex
+ for(i=0;i<MAX_WIS_REFUSAL;i++){ //すでに追加されていれば何もしない
+ if(strcmp(sd->wis_refusal[i],RFIFOP(fd,packet_db[cmd].pos[0]))==0){
+ flag=0;
+ clif_wisexin(sd, type, flag);
+ return;
+ }
+ }
+ for(i=0;i<MAX_WIS_REFUSAL;i++){ //空の拒否リストに追加(とりあえず)
+ if(sd->wis_refusal[i][0]==0){
+ memcpy(sd->wis_refusal[i],RFIFOP(fd,packet_db[cmd].pos[0]),24);
+ flag=0;
+ break;
+ }
+ }
+ if(flag==1){
+ memcpy(sd->wis_refusal[MAX_WIS_REFUSAL-1],RFIFOP(fd,packet_db[cmd].pos[0]),24);
+ flag=0;
+ }
+ }else{ //in
+ for(i=0;i<MAX_WIS_REFUSAL;i++){ //一致する拒否リストを空に
+ if(strcmp(sd->wis_refusal[i],RFIFOP(fd,packet_db[cmd].pos[0]))==0){
+ sd->wis_refusal[i][0]=0;
+ flag=0;
+ }
+ }
+ sd->wis_all = 0;
+ }
+ clif_wisexin(sd, type, flag);
+ }
+ return;
+}
+
+/*==========================================
+ * View Whisper List [ /ex ]
+ *------------------------------------------
+ */
+void clif_parse_wisexlist(int fd,struct map_session_data *sd, int cmd)
+{
+ int i,j=0,count=0;
+
+ if(sd){
+ qsort(sd->wis_refusal[0], MAX_WIS_REFUSAL, sizeof(sd->wis_refusal[0]), pstrcmp);
+ for(i=0;i<MAX_WIS_REFUSAL;i++){ //中身があるのを数える
+ if(sd->wis_refusal[i][0]!=0)
+ count++;
+ }
+ WFIFOW(fd,0)=0xd4;
+ WFIFOW(fd,2)=4+(24*count);
+ for(i=0;i<MAX_WIS_REFUSAL;i++){
+ if(sd->wis_refusal[i][0]!=0){
+ memcpy(WFIFOP(fd,4+j*24),sd->wis_refusal[i],24);
+ j++;
+ }
+ }
+ WFIFOSET(fd,WFIFOW(fd,2));
+ if(count>=MAX_WIS_REFUSAL) //満タンなら最後の1個を消す
+ sd->wis_refusal[MAX_WIS_REFUSAL-1][0]=0;
+ }
+
+ return;
+}
+
+/*==========================================
+ * Block and Allow all Whispers /exall /inall
+ *------------------------------------------
+ */
+void clif_parse_wisall(int fd,struct map_session_data *sd, int cmd)
+{
+ int type = RFIFOB(fd,packet_db[cmd].pos[0]);
+ int i;
+
+ if(sd){
+ if(type==0) //exall
+ sd->wis_all = 1;
+ else{ //inall
+ for(i=0;i<MAX_WIS_REFUSAL;i++) //拒否リストを空に
+ sd->wis_refusal[i][0]=0;
+ sd->wis_all = 0;
+ }
+ clif_wisall(sd, type, 0);
+ }
+}
+
+/*==========================================
+ * /killall
+ *------------------------------------------
+ */
+void clif_parse_GMkillall(int fd,struct map_session_data *sd, int cmd)
+{
+ char message[50];
+
+ nullpo_retv(sd);
+
+ strncpy(message,sd->status.name,24);
+ is_atcommand(fd,sd,strcat(message," : @kickall"),0);
+ return;
+}
+
+/*==========================================
+ * /summon
+ *------------------------------------------
+ */
+void clif_parse_GMsummon(int fd,struct map_session_data *sd, int cmd)
+{
+ char message[100];
+
+ nullpo_retv(sd);
+
+ strncpy(message,sd->status.name,24);
+ strcat(message," : @recall ");
+ strncat(message,RFIFOP(fd,packet_db[cmd].pos[0]),24);
+ is_atcommand(fd,sd,message,0);
+ return;
+}
+/*==========================================
+ * /shift
+ *------------------------------------------
+ */
+void clif_parse_GMshift(int fd,struct map_session_data *sd, int cmd)
+{
+ char message[100];
+
+ nullpo_retv(sd);
+
+ strncpy(message,sd->status.name,24);
+ strcat(message," : @jumpto ");
+ strncat(message,RFIFOP(fd,packet_db[cmd].pos[0]),24);
+ is_atcommand(fd,sd,message,0);
+ return;
+}
+/*==========================================
+ * Debugging
+ *------------------------------------------
+ */
+void clif_parse_debug(int fd,struct map_session_data *sd, int cmd)
+{
+ int i;
+
+ printf("packet debug 0x%4X\n",cmd);
+ printf("---- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F");
+ for(i=0;i<packet_db[cmd].len;i++){
+ if((i&15)==0)
+ printf("\n%04X ",i);
+ printf("%02X ",RFIFOB(fd,i));
+ }
+ printf("\n");
+}
+
+/*==========================================
+ * クライアントからのパケット解析
+ * socket.cのdo_parsepacketから呼び出される
+ *------------------------------------------
+ */
+static int clif_parse(int fd) {
+ int packet_len = 0, cmd;
+ struct map_session_data *sd;
+
+ sd = session[fd]->session_data;
+
+ // 接続が切れてるので後始末
+ if (!chrif_isconnect() || session[fd]->eof) { // char鯖に繋がってない間は接続禁止 (!chrif_isconnect())
+ if (sd && sd->state.auth) {
+ clif_quitsave(fd, sd);
+ } else if (sd) { // not authentified! (refused by char-server or disconnect before to be authentified)
+// printf("Player with account [%d] has logged off your server (not auth account).\n", sd->bl.id); // Player logout display [Yor]
+ map_deliddb(&sd->bl); // account_id has been included in the DB before auth answer
+ }
+ close(fd);
+ delete_session(fd);
+ return 0;
+ }
+
+ if (RFIFOREST(fd) < 2)
+ return 0;
+
+ cmd = RFIFOW(fd,0);
+
+ // 管理用パケット処理
+ if (cmd >= 30000) {
+ switch(cmd) {
+ case 0x7530: // Athena情報所得
+ WFIFOW(fd,0) = 0x7531;
+ WFIFOB(fd,2) = ATHENA_MAJOR_VERSION;
+ WFIFOB(fd,3) = ATHENA_MINOR_VERSION;
+ WFIFOB(fd,4) = ATHENA_REVISION;
+ WFIFOB(fd,5) = ATHENA_RELEASE_FLAG;
+ WFIFOB(fd,6) = ATHENA_OFFICIAL_FLAG;
+ WFIFOB(fd,7) = ATHENA_SERVER_MAP;
+ WFIFOW(fd,8) = ATHENA_MOD_VERSION;
+ WFIFOSET(fd,10);
+ RFIFOSKIP(fd,2);
+ break;
+ case 0x7532: // 接続の切断
+ session[fd]->eof = 1;
+ break;
+ }
+ return 0;
+ }
+
+ // ゲーム用以外パケットか、認証を終える前に0072以外が来たら、切断する
+ if(cmd>=MAX_PACKET_DB || packet_db[cmd].len==0 ||
+ ((!sd || (sd && sd->state.auth==0)) && packet_db[cmd].func!=clif_parse_WantToConnection) ){
+
+ close(fd);
+ session[fd]->eof = 1;
+ if(packet_db[cmd].len==0) {
+ printf("clif_parse : %d %d %x\n",fd,packet_db[cmd].len,cmd);
+ printf("%x length 0 packet disconnect %d\n",cmd,fd);
+ }
+ return 0;
+ }
+
+ // パケット長を計算
+ packet_len = packet_db[cmd].len;
+ if(packet_len==-1){
+ if(RFIFOREST(fd)<4)
+ return 0; // 可変長パケットで長さの所までデータが来てない
+ packet_len = RFIFOW(fd,2);
+ if(packet_len<4 || packet_len>32768){
+ close(fd);
+ session[fd]->eof =1;
+ return 0;
+ }
+ }
+ if (RFIFOREST(fd) < packet_len)
+ return 0; // まだ1パケット分データが揃ってない
+
+ if (sd && sd->state.auth == 1 && sd->state.waitingdisconnect == 1) { // 切断待ちの場合パケットを処理しない
+
+ }else if(packet_db[cmd].func){
+ // パケット処理
+ packet_db[cmd].func(fd,sd,cmd);
+ } else {
+ // 不明なパケット
+ if (battle_config.error_log) {
+ if (fd)
+ printf("\nclif_parse: session #%d, packet 0x%x, lenght %d\n", fd, cmd, packet_len);
+#ifdef DUMP_UNKNOWN_PACKET
+ {
+ int i;
+ FILE *fp;
+ char packet_txt[256] = "save/packet.txt";
+ time_t now;
+ printf("---- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F");
+ for(i = 0; i < packet_len; i++) {
+ if ((i & 15) == 0)
+ printf("\n%04X ",i);
+ printf("%02X ", RFIFOB(fd,i));
+ }
+ if (sd && sd->state.auth) {
+ if (sd->status.name != NULL)
+ printf("\nAccount ID %d, character ID %d, player name %s.\n",
+ sd->status.account_id, sd->status.char_id, sd->status.name);
+ else
+ printf("\nAccount ID %d.\n", sd->bl.id);
+ } else if (sd) // not authentified! (refused by char-server or disconnect before to be authentified)
+ printf("\nAccount ID %d.\n", sd->bl.id);
+
+ if ((fp = fopen(packet_txt, "a")) == NULL) {
+ printf("clif.c: cant write [%s] !!! data is lost !!!\n", packet_txt);
+ return 1;
+ } else {
+ time(&now);
+ if (sd && sd->state.auth) {
+ if (sd->status.name != NULL)
+ fprintf(fp, "%sPlayer with account ID %d (character ID %d, player name %s) sent wrong packet:\n",
+ asctime(localtime(&now)), sd->status.account_id, sd->status.char_id, sd->status.name);
+ else
+ fprintf(fp, "%sPlayer with account ID %d sent wrong packet:\n", asctime(localtime(&now)), sd->bl.id);
+ } else if (sd) // not authentified! (refused by char-server or disconnect before to be authentified)
+ fprintf(fp, "%sPlayer with account ID %d sent wrong packet:\n", asctime(localtime(&now)), sd->bl.id);
+
+ fprintf(fp, "\t---- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F");
+ for(i = 0; i < packet_len; i++) {
+ if ((i & 15) == 0)
+ fprintf(fp, "\n\t%04X ", i);
+ fprintf(fp, "%02X ", RFIFOB(fd,i));
+ }
+ fprintf(fp, "\n\n");
+ fclose(fp);
+ }
+ }
+#endif
+ }
+ }
+ RFIFOSKIP(fd, packet_len);
+
+ return 0;
+}
+
+/*==========================================
+ * Read the Packet Database file.
+ *------------------------------------------
+ */
+static int packetdb_readdb(void)
+{
+ FILE *fp;
+ char line[1024];
+ int ln=0;
+ int cmd,j;
+ char *str[32],*p,*str2[32],*p2;
+
+ memset(packet_db,0,sizeof(packet_db));
+
+ if( (fp=fopen("db/packet_db.txt","r"))==NULL ){
+ printf("can't read db/packet_db.txt\n");
+ exit(1);
+ }
+ while(fgets(line,1020,fp)){
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ memset(str,0,sizeof(str));
+ for(j=0,p=line;j<4 && p;j++){
+ str[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+ if(str[0]==NULL)
+ continue;
+
+ cmd=strtol(str[0],(char **)NULL,0);
+ if(cmd<=0 || cmd>=MAX_PACKET_DB)
+ continue;
+
+ if(str[1]==NULL){
+ printf("packet_db: packet len error\n");
+ exit(1);
+ }
+ packet_db[cmd].len = atoi(str[1]);
+
+ if(str[2]==NULL){
+ ln++;
+ continue;
+ }
+ for(j=0;j<sizeof(clif_parse_func)/sizeof(clif_parse_func[0]);j++){
+ if(clif_parse_func[j].name == NULL){
+ printf("packet_db: %d 0x%x no func %s\n",ln+1,cmd,str[2]);
+ exit(1);
+ }
+ if( strcmp(str[2],clif_parse_func[j].name)==0){
+ packet_db[cmd].func=clif_parse_func[j].func;
+ break;
+ }
+ }
+ if(str[3]==NULL){
+ printf("packet_db: packet error\n");
+ exit(1);
+ }
+ for(j=0,p2=str[3];p2;j++){
+ str2[j]=p2;
+ p2=strchr(p2,':');
+ if(p2) *p2++=0;
+ packet_db[cmd].pos[j]=atoi(str2[j]);
+ }
+
+ ln++;
+// if(packet_db[cmd].len > 2 && packet_db[cmd].pos[0] == 0)
+// printf("packet_db:? %d 0x%x %d %s %p\n",ln,cmd,packet_db[cmd].len,str[2],packet_db[cmd].func);
+ }
+ fclose(fp);
+ printf("read db/packet_db.txt done (Packets=%d)\n",ln);
+ return 0;
+
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int do_init_clif(void) {
+ int i;
+
+ packetdb_readdb();
+ set_defaultparse(clif_parse);
+ for(i = 0; i < 10; i++) {
+ if (make_listen_port(map_port))
+ break;
+#ifdef _WIN32
+ Sleep(20000);
+#else
+ sleep(20);
+#endif
+ }
+ if (i == 10) {
+ printf("cant bind game port\n");
+ exit(1);
+ }
+
+ add_timer_func_list(clif_waitclose, "clif_waitclose");
+ add_timer_func_list(clif_clearchar_delay_sub, "clif_clearchar_delay_sub");
+
+ return 0;
+}
+
diff --git a/src/map/clif.h b/src/map/clif.h
new file mode 100644
index 000000000..5a04d41d6
--- /dev/null
+++ b/src/map/clif.h
@@ -0,0 +1,297 @@
+// $Id: clif.h,v 1.4 2004/09/25 05:32:18 MouseJstr Exp $
+#ifndef _CLIF_H_
+#define _CLIF_H_
+
+#include <sys/types.h>
+
+#ifdef _WIN32
+#include <winsock.h>
+typedef unsigned int in_addr_t;
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#include "map.h"
+
+#define MAX_PACKET_DB 0x220
+
+struct packet_db {
+ short len;
+ void (*func)();
+ short pos[20];
+};
+
+void clif_setip(char*);
+void clif_setport(int);
+
+in_addr_t clif_getip(void);
+int clif_getport(void);
+int clif_countusers(void);
+void clif_setwaitclose(int);
+
+int clif_authok(struct map_session_data *);
+int clif_authfail_fd(int,int);
+int clif_charselectok(int);
+int clif_dropflooritem(struct flooritem_data *);
+int clif_clearflooritem(struct flooritem_data *,int);
+int clif_clearchar(struct block_list*,int); // area or fd
+int clif_clearchar_delay(unsigned int,struct block_list *,int);
+#define clif_clearchar_area(bl,type) clif_clearchar(bl,type)
+int clif_clearchar_id(int,int,int);
+int clif_spawnpc(struct map_session_data*); //area
+int clif_spawnnpc(struct npc_data*); // area
+int clif_spawnmob(struct mob_data*); // area
+int clif_spawnpet(struct pet_data*); // area
+int clif_walkok(struct map_session_data*); // self
+int clif_movechar(struct map_session_data*); // area
+int clif_movemob(struct mob_data*); //area
+int clif_movepet(struct pet_data *pd); //area
+int clif_movenpc(struct npc_data *nd); // [Valaris]
+int clif_changemap(struct map_session_data*,char*,int,int); //self
+int clif_changemapserver(struct map_session_data*,char*,int,int,int,int); //self
+int clif_fixpos(struct block_list *); // area
+int clif_fixmobpos(struct mob_data *md);
+int clif_fixpcpos(struct map_session_data *sd);
+int clif_fixpetpos(struct pet_data *pd);
+int clif_fixnpcpos(struct npc_data *nd); // [Valaris]
+int clif_npcbuysell(struct map_session_data*,int); //self
+int clif_buylist(struct map_session_data*,struct npc_data*); //self
+int clif_selllist(struct map_session_data*); //self
+int clif_scriptmes(struct map_session_data*,int,char*); //self
+int clif_scriptnext(struct map_session_data*,int); //self
+int clif_scriptclose(struct map_session_data*,int); //self
+int clif_scriptmenu(struct map_session_data*,int,char*); //self
+int clif_scriptinput(struct map_session_data*,int); //self
+int clif_scriptinputstr(struct map_session_data *sd,int npcid); // self
+int clif_cutin(struct map_session_data*,char*,int); //self
+int clif_viewpoint(struct map_session_data*,int,int,int,int,int,int); //self
+int clif_additem(struct map_session_data*,int,int,int); //self
+int clif_delitem(struct map_session_data*,int,int); //self
+int clif_updatestatus(struct map_session_data*,int); //self
+int clif_changestatus(struct block_list*,int,int); //area
+int clif_damage(struct block_list *,struct block_list *,unsigned int,int,int,int,int,int,int); // area
+#define clif_takeitem(src,dst) clif_damage(src,dst,0,0,0,0,0,1,0)
+int clif_changelook(struct block_list *,int,int); // area
+int clif_arrowequip(struct map_session_data *sd,int val); //self
+int clif_arrow_fail(struct map_session_data *sd,int type); //self
+int clif_arrow_create_list(struct map_session_data *sd); //self
+int clif_statusupack(struct map_session_data *,int,int,int); // self
+int clif_equipitemack(struct map_session_data *,int,int,int); // self
+int clif_unequipitemack(struct map_session_data *,int,int,int); // self
+int clif_misceffect(struct block_list*,int); // area
+int clif_misceffect2(struct block_list *bl,int type);
+int clif_changeoption(struct block_list*); // area
+int clif_useitemack(struct map_session_data*,int,int,int); // self
+
+int clif_createchat(struct map_session_data*,int); // self
+int clif_dispchat(struct chat_data*,int); // area or fd
+int clif_joinchatfail(struct map_session_data*,int); // self
+int clif_joinchatok(struct map_session_data*,struct chat_data*); // self
+int clif_addchat(struct chat_data*,struct map_session_data*); // chat
+int clif_changechatowner(struct chat_data*,struct map_session_data*); // chat
+int clif_clearchat(struct chat_data*,int); // area or fd
+int clif_leavechat(struct chat_data*,struct map_session_data*); // chat
+int clif_changechatstatus(struct chat_data*); // chat
+
+void clif_emotion(struct block_list *bl,int type);
+void clif_talkiebox(struct block_list *bl,char* talkie);
+void clif_wedding_effect(struct block_list *bl);
+void clif_sitting(int fd, struct map_session_data *sd);
+//void clif_callpartner(struct map_session_data *sd);
+//void clif_sitting(struct map_session_data *sd);
+void clif_soundeffect(struct map_session_data *sd,struct block_list *bl,char *name,int type);
+
+// trade
+int clif_traderequest(struct map_session_data *sd,char *name);
+int clif_tradestart(struct map_session_data *sd,int type);
+int clif_tradeadditem(struct map_session_data *sd,struct map_session_data *tsd,int index,int amount);
+int clif_tradeitemok(struct map_session_data *sd,int index,int fail);
+int clif_tradedeal_lock(struct map_session_data *sd,int fail);
+int clif_tradecancelled(struct map_session_data *sd);
+int clif_tradecompleted(struct map_session_data *sd,int fail);
+
+// storage
+#include "storage.h"
+int clif_storageitemlist(struct map_session_data *sd,struct storage *stor);
+int clif_storageequiplist(struct map_session_data *sd,struct storage *stor);
+int clif_updatestorageamount(struct map_session_data *sd,struct storage *stor);
+int clif_storageitemadded(struct map_session_data *sd,struct storage *stor,int index,int amount);
+int clif_storageitemremoved(struct map_session_data *sd,int index,int amount);
+int clif_storageclose(struct map_session_data *sd);
+int clif_guildstorageitemlist(struct map_session_data *sd,struct guild_storage *stor);
+int clif_guildstorageequiplist(struct map_session_data *sd,struct guild_storage *stor);
+int clif_updateguildstorageamount(struct map_session_data *sd,struct guild_storage *stor);
+int clif_guildstorageitemadded(struct map_session_data *sd,struct guild_storage *stor,int index,int amount);
+
+int clif_pcinsight(struct block_list *,va_list); // map_forallinmovearea callback
+int clif_pcoutsight(struct block_list *,va_list); // map_forallinmovearea callback
+int clif_mobinsight(struct block_list *,va_list); // map_forallinmovearea callback
+int clif_moboutsight(struct block_list *,va_list); // map_forallinmovearea callback
+int clif_petoutsight(struct block_list *bl,va_list ap);
+int clif_petinsight(struct block_list *bl,va_list ap);
+int clif_npcoutsight(struct block_list *bl,va_list ap);
+int clif_npcinsight(struct block_list *bl,va_list ap);
+
+int clif_class_change(struct block_list *bl,int class,int type);
+int clif_mob_class_change(struct mob_data *md,int class);
+int clif_mob_equip(struct mob_data *md,int nameid); // [Valaris]
+
+int clif_skillinfo(struct map_session_data *sd,int skillid,int type,int range);
+int clif_skillinfoblock(struct map_session_data *sd);
+int clif_skillup(struct map_session_data *sd,int skill_num);
+
+int clif_skillcasting(struct block_list* bl,
+ int src_id,int dst_id,int dst_x,int dst_y,int skill_num,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_damage(struct block_list *src,struct block_list *dst,
+ unsigned int tick,int sdelay,int ddelay,int damage,int div,
+ int skill_id,int skill_lv,int type);
+int clif_skill_damage2(struct block_list *src,struct block_list *dst,
+ unsigned int tick,int sdelay,int ddelay,int damage,int div,
+ int skill_id,int skill_lv,int type);
+int clif_skill_nodamage(struct block_list *src,struct block_list *dst,
+ int skill_id,int heal,int fail);
+int clif_skill_poseffect(struct block_list *src,int skill_id,
+ int val,int x,int y,int tick);
+int clif_skill_estimation(struct map_session_data *sd,struct block_list *dst);
+int clif_skill_warppoint(struct map_session_data *sd,int skill_num,
+ const char *map1,const char *map2,const char *map3,const char *map4);
+int clif_skill_memo(struct map_session_data *sd,int flag);
+int clif_skill_teleportmessage(struct map_session_data *sd,int flag);
+int clif_skill_produce_mix_list(struct map_session_data *sd,int trigger);
+
+int clif_produceeffect(struct map_session_data *sd,int flag,int nameid);
+
+int clif_skill_setunit(struct skill_unit *unit);
+int clif_skill_delunit(struct skill_unit *unit);
+
+int clif_01ac(struct block_list *bl);
+
+int clif_autospell(struct map_session_data *sd,int skilllv);
+int clif_devotion(struct map_session_data *sd,int target);
+int clif_spiritball(struct map_session_data *sd);
+int clif_combo_delay(struct block_list *src,int wait);
+int clif_bladestop(struct block_list *src,struct block_list *dst,int bool);
+int clif_changemapcell(int m,int x,int y,int cell_type,int type);
+
+int clif_status_change(struct block_list *bl,int type,int flag);
+
+int clif_wis_message(int fd,char *nick,char *mes,int mes_len);
+int clif_wis_end(int fd,int flag);
+
+int clif_solved_charname(struct map_session_data *sd,int char_id);
+
+int clif_use_card(struct map_session_data *sd,int idx);
+int clif_insert_card(struct map_session_data *sd,int idx_equip,int idx_card,int flag);
+
+int clif_itemlist(struct map_session_data *sd);
+int clif_equiplist(struct map_session_data *sd);
+
+int clif_cart_additem(struct map_session_data*,int,int,int);
+int clif_cart_delitem(struct map_session_data*,int,int);
+int clif_cart_itemlist(struct map_session_data *sd);
+int clif_cart_equiplist(struct map_session_data *sd);
+
+int clif_item_identify_list(struct map_session_data *sd);
+int clif_item_identified(struct map_session_data *sd,int idx,int flag);
+int clif_item_repair_list(struct map_session_data *sd);
+
+int clif_item_skill(struct map_session_data *sd,int skillid,int skilllv,const char *name);
+
+int clif_mvp_effect(struct map_session_data *sd);
+int clif_mvp_item(struct map_session_data *sd,int nameid);
+int clif_mvp_exp(struct map_session_data *sd,int exp);
+
+// vending
+int clif_openvendingreq(struct map_session_data *sd,int num);
+int clif_showvendingboard(struct block_list* bl,char *message,int fd);
+int clif_closevendingboard(struct block_list* bl,int fd);
+int clif_vendinglist(struct map_session_data *sd,int id,struct vending *vending);
+int clif_buyvending(struct map_session_data *sd,int index,int amount,int fail);
+int clif_openvending(struct map_session_data *sd,int id,struct vending *vending);
+int clif_vendingreport(struct map_session_data *sd,int index,int amount);
+
+int clif_movetoattack(struct map_session_data *sd,struct block_list *bl);
+
+// party
+int clif_party_created(struct map_session_data *sd,int flag);
+int clif_party_info(struct party *p,int fd);
+int clif_party_invite(struct map_session_data *sd,struct map_session_data *tsd);
+int clif_party_inviteack(struct map_session_data *sd,char *nick,int flag);
+int clif_party_option(struct party *p,struct map_session_data *sd,int flag);
+int clif_party_leaved(struct party *p,struct map_session_data *sd,int account_id,char *name,int flag);
+int clif_party_message(struct party *p,int account_id,char *mes,int len);
+int clif_party_move(struct party *p,struct map_session_data *sd,int online);
+int clif_party_xy(struct party *p,struct map_session_data *sd);
+int clif_party_hp(struct party *p,struct map_session_data *sd);
+
+// guild
+int clif_guild_created(struct map_session_data *sd,int flag);
+int clif_guild_belonginfo(struct map_session_data *sd,struct guild *g);
+int clif_guild_basicinfo(struct map_session_data *sd);
+int clif_guild_allianceinfo(struct map_session_data *sd);
+int clif_guild_memberlist(struct map_session_data *sd);
+int clif_guild_skillinfo(struct map_session_data *sd);
+int clif_guild_memberlogin_notice(struct guild *g,int idx,int flag);
+int clif_guild_invite(struct map_session_data *sd,struct guild *g);
+int clif_guild_inviteack(struct map_session_data *sd,int flag);
+int clif_guild_leave(struct map_session_data *sd,const char *name,const char *mes);
+int clif_guild_explusion(struct map_session_data *sd,const char *name,const char *mes,
+ int account_id);
+int clif_guild_positionchanged(struct guild *g,int idx);
+int clif_guild_memberpositionchanged(struct guild *g,int idx);
+int clif_guild_emblem(struct map_session_data *sd,struct guild *g);
+int clif_guild_notice(struct map_session_data *sd,struct guild *g);
+int clif_guild_message(struct guild *g,int account_id,const char *mes,int len);
+int clif_guild_skillup(struct map_session_data *sd,int skill_num,int lv);
+int clif_guild_reqalliance(struct map_session_data *sd,int account_id,const char *name);
+int clif_guild_allianceack(struct map_session_data *sd,int flag);
+int clif_guild_delalliance(struct map_session_data *sd,int guild_id,int flag);
+int clif_guild_oppositionack(struct map_session_data *sd,int flag);
+int clif_guild_broken(struct map_session_data *sd,int flag);
+
+
+// atcommand
+int clif_displaymessage(const int fd,char* mes);
+int clif_disp_onlyself(struct map_session_data *sd,char *mes,int len);
+int clif_GMmessage(struct block_list *bl,char* mes,int len,int flag);
+int clif_heal(int fd,int type,int val);
+int clif_resurrection(struct block_list *bl,int type);
+int clif_set0199(int fd,int type);
+int clif_pvpset(struct map_session_data *sd, int pvprank, int pvpnum,int type);
+int clif_send0199(int map,int type);
+int clif_refine(int fd,struct map_session_data *sd,int fail,int index,int val);
+
+//petsystem
+int clif_catch_process(struct map_session_data *sd);
+int clif_pet_rulet(struct map_session_data *sd,int data);
+int clif_sendegg(struct map_session_data *sd);
+int clif_send_petdata(struct map_session_data *sd,int type,int param);
+int clif_send_petstatus(struct map_session_data *sd);
+int clif_pet_emotion(struct pet_data *pd,int param);
+int clif_pet_performance(struct block_list *bl,int param);
+int clif_pet_equip(struct pet_data *pd,int nameid);
+int clif_pet_food(struct map_session_data *sd,int foodid,int fail);
+
+//friends list
+void clif_friends_list_send(struct map_session_data *sd);
+void clif_parse_friends_list_add(int fd,struct map_session_data *sd);
+void clif_parse_friends_list_remove(int fd,struct map_session_data *sd);
+
+int clif_specialeffect(struct block_list *bl,int type, int flag); // special effects [Valaris]
+int clif_message(struct block_list *bl, char* msg); // messages (from mobs/npcs) [Valaris]
+
+int clif_GM_kickack(struct map_session_data *sd,int id);
+int clif_GM_kick(struct map_session_data *sd,struct map_session_data *tsd,int type);
+
+int clif_foreachclient(int (*)(struct map_session_data*,va_list),...);
+
+int do_final_clif(void);
+int do_init_clif(void);
+
+#endif
+
+
diff --git a/src/map/guild.c b/src/map/guild.c
new file mode 100644
index 000000000..164cf9827
--- /dev/null
+++ b/src/map/guild.c
@@ -0,0 +1,1554 @@
+// $Id: guild.c,v 1.5 2004/09/25 05:32:18 MouseJstr Exp $
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "guild.h"
+#include "storage.h"
+#include "db.h"
+#include "timer.h"
+#include "socket.h"
+#include "nullpo.h"
+#include "malloc.h"
+#include "battle.h"
+#include "npc.h"
+#include "pc.h"
+#include "map.h"
+#include "mob.h"
+#include "intif.h"
+#include "clif.h"
+#include "skill.h"
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+static struct dbt *guild_db;
+static struct dbt *castle_db;
+static struct dbt *guild_expcache_db;
+static struct dbt *guild_infoevent_db;
+static struct dbt *guild_castleinfoevent_db;
+
+struct eventlist {
+ char name[50];
+ struct eventlist *next;
+};
+
+// ギルドのEXPキャッシュのフラッシュに関連する定数
+#define GUILD_PAYEXP_INVERVAL 10000 // 間隔(キャッシュの最大生存時間、ミリ秒)
+#define GUILD_PAYEXP_LIST 8192 // キャッシュの最大数
+
+// ギルドのEXPキャッシュ
+struct guild_expcache {
+ int guild_id, account_id, char_id, exp;
+};
+
+// ギルドスキルdbのアクセサ(今は直打ちで代用)
+int guild_skill_get_inf(int id) { // Modified for new skills [Sara]
+ if (id==GD_BATTLEORDER) return 4;
+ else if (id==GD_REGENERATION) return 4;
+ else if (id==GD_RESTORE) return 4;
+ else if (id==GD_EMERGENCYCALL) return 4;
+ else return 0;
+}
+int guild_skill_get_sp(int id,int lv){ return 0; }
+int guild_skill_get_range(int id){ return 0; }
+int guild_skill_get_max(int id) { // Modified for new skills [Sara]
+ if (id==GD_EXTENSION) return 10;
+ else if (id==GD_REGENERATION) return 3;
+ else return 1;
+}
+
+// ギルドスキルがあるか確認
+int guild_checkskill(struct guild *g,int id){ return g->skill[id-10000].lv; }
+
+
+int guild_payexp_timer(int tid,unsigned int tick,int id,int data);
+int guild_gvg_eliminate_timer(int tid,unsigned int tick,int id,int data);
+
+
+static int guild_read_castledb(void)
+{
+ FILE *fp;
+ char line[1024];
+ int j,ln=0;
+ char *str[32],*p;
+ struct guild_castle *gc;
+
+ if( (fp=fopen("db/castle_db.txt","r"))==NULL){
+ printf("can't read db/castle_db.txt\n");
+ return -1;
+ }
+
+ while(fgets(line,1020,fp)){
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ memset(str,0,sizeof(str));
+ gc=(struct guild_castle *)aCalloc(1,sizeof(struct guild_castle));
+ for(j=0,p=line;j<6 && p;j++){
+ str[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+
+ gc->guild_id=0; // <Agit> Clear Data for Initialize
+ gc->economy=0; gc->defense=0; gc->triggerE=0; gc->triggerD=0; gc->nextTime=0; gc->payTime=0;
+ gc->createTime=0; gc->visibleC=0; gc->visibleG0=0; gc->visibleG1=0; gc->visibleG2=0;
+ gc->visibleG3=0; gc->visibleG4=0; gc->visibleG5=0; gc->visibleG6=0; gc->visibleG7=0;
+ gc->Ghp0=0; gc->Ghp1=0; gc->Ghp2=0; gc->Ghp3=0; gc->Ghp4=0; gc->Ghp5=0; gc->Ghp6=0; gc->Ghp7=0; // guardian HP [Valaris]
+
+ gc->castle_id=atoi(str[0]);
+ memcpy(gc->map_name,str[1],24);
+ memcpy(gc->castle_name,str[2],24);
+ memcpy(gc->castle_event,str[3],24);
+
+ numdb_insert(castle_db,gc->castle_id,gc);
+
+ //intif_guild_castle_info(gc->castle_id);
+
+ ln++;
+ }
+ fclose(fp);
+ printf("read db/castle_db.txt done (count=%d)\n",ln);
+ return 0;
+}
+
+// 初期化
+void do_init_guild(void)
+{
+ guild_db=numdb_init();
+ castle_db=numdb_init();
+ guild_expcache_db=numdb_init();
+ guild_infoevent_db=numdb_init();
+ guild_castleinfoevent_db=numdb_init();
+
+ guild_read_castledb();
+
+ add_timer_func_list(guild_gvg_eliminate_timer,"guild_gvg_eliminate_timer");
+ add_timer_func_list(guild_payexp_timer,"guild_payexp_timer");
+ add_timer_interval(gettick()+GUILD_PAYEXP_INVERVAL,guild_payexp_timer,0,0,GUILD_PAYEXP_INVERVAL);
+}
+
+
+// 検索
+struct guild *guild_search(int guild_id)
+{
+ return numdb_search(guild_db,guild_id);
+}
+int guild_searchname_sub(void *key,void *data,va_list ap)
+{
+ struct guild *g=(struct guild *)data,**dst;
+ char *str;
+ str=va_arg(ap,char *);
+ dst=va_arg(ap,struct guild **);
+ if(strcmpi(g->name,str)==0)
+ *dst=g;
+ return 0;
+}
+// ギルド名検索
+struct guild* guild_searchname(char *str)
+{
+ struct guild *g=NULL;
+ numdb_foreach(guild_db,guild_searchname_sub,str,&g);
+ return g;
+}
+struct guild_castle *guild_castle_search(int gcid)
+{
+ return numdb_search(castle_db,gcid);
+}
+
+// mapnameに対応したアジトのgcを返す
+struct guild_castle *guild_mapname2gc(char *mapname)
+{
+ int i;
+ struct guild_castle *gc=NULL;
+ for(i=0;i<MAX_GUILDCASTLE;i++){
+ gc=guild_castle_search(i);
+ if(!gc) continue;
+ if(strcmp(gc->map_name,mapname)==0) return gc;
+ }
+ return NULL;
+}
+
+// ログイン中のギルドメンバーの1人のsdを返す
+struct map_session_data *guild_getavailablesd(struct guild *g)
+{
+ int i;
+
+ nullpo_retr(NULL, g);
+
+ for(i=0;i<g->max_member;i++)
+ if(g->member[i].sd!=NULL)
+ return g->member[i].sd;
+ return NULL;
+}
+
+// ギルドメンバーのインデックスを返す
+int guild_getindex(struct guild *g,int account_id,int char_id)
+{
+ int i;
+ if(g==NULL)
+ return -1;
+ for(i=0;i<g->max_member;i++)
+ if( g->member[i].account_id==account_id &&
+ g->member[i].char_id==char_id )
+ return i;
+ return -1;
+}
+// ギルドメンバーの役職を返す
+int guild_getposition(struct map_session_data *sd,struct guild *g)
+{
+ int i;
+
+ nullpo_retr(-1, sd);
+
+ if(g==NULL && (g=guild_search(sd->status.guild_id))==NULL)
+ return -1;
+ for(i=0;i<g->max_member;i++)
+ if( g->member[i].account_id==sd->status.account_id &&
+ g->member[i].char_id==sd->status.char_id )
+ return g->member[i].position;
+ return -1;
+}
+
+// メンバー情報の作成
+void guild_makemember(struct guild_member *m,struct map_session_data *sd)
+{
+ nullpo_retv(sd);
+
+ memset(m,0,sizeof(struct guild_member));
+ m->account_id =sd->status.account_id;
+ m->char_id =sd->status.char_id;
+ m->hair =sd->status.hair;
+ m->hair_color =sd->status.hair_color;
+ m->gender =sd->sex;
+ m->class =sd->status.class;
+ m->lv =sd->status.base_level;
+ m->exp =0;
+ m->exp_payper =0;
+ m->online =1;
+ m->position =MAX_GUILDPOSITION-1;
+ memcpy(m->name,sd->status.name,24);
+ return;
+}
+// ギルド競合確認
+int guild_check_conflict(struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+
+ intif_guild_checkconflict(sd->status.guild_id,
+ sd->status.account_id,sd->status.char_id);
+ return 0;
+}
+
+// ギルドのEXPキャッシュをinter鯖にフラッシュする
+int guild_payexp_timer_sub(void *key,void *data,va_list ap)
+{
+ int i, *dellist,*delp, dataid=(int)key;
+ struct guild_expcache *c;
+ struct guild *g;
+
+ nullpo_retr(0, ap);
+ nullpo_retr(0, c=(struct guild_expcache *)data);
+ nullpo_retr(0, dellist=va_arg(ap,int *));
+ nullpo_retr(0, delp=va_arg(ap,int *));
+
+ if( *delp>=GUILD_PAYEXP_LIST || (g=guild_search(c->guild_id))==NULL )
+ return 0;
+ if( ( i=guild_getindex(g,c->account_id,c->char_id) )<0 )
+ return 0;
+
+ g->member[i].exp+=c->exp;
+ intif_guild_change_memberinfo(g->guild_id,c->account_id,c->char_id,
+ GMI_EXP,&g->member[i].exp,sizeof(g->member[i].exp));
+ c->exp=0;
+
+ dellist[(*delp)++]=dataid;
+ free(c);
+ return 0;
+}
+int guild_payexp_timer(int tid,unsigned int tick,int id,int data)
+{
+ int dellist[GUILD_PAYEXP_LIST],delp=0,i;
+ numdb_foreach(guild_expcache_db,guild_payexp_timer_sub,
+ dellist,&delp);
+ for(i=0;i<delp;i++)
+ numdb_erase(guild_expcache_db,dellist[i]);
+// if(battle_config.etc_log)
+// printf("guild exp %d charactor's exp flushed !\n",delp);
+ return 0;
+}
+
+//------------------------------------------------------------------------
+
+// 作成要求
+int guild_create(struct map_session_data *sd,char *name)
+{
+ nullpo_retr(0, sd);
+
+ if(sd->status.guild_id==0){
+ if(!battle_config.guild_emperium_check || pc_search_inventory(sd,714) >= 0) {
+ struct guild_member m;
+ guild_makemember(&m,sd);
+ m.position=0;
+ intif_guild_create(name,&m);
+ } else
+ clif_guild_created(sd,3); // エンペリウムがいない
+ }else
+ clif_guild_created(sd,1); // すでに所属している
+
+ return 0;
+}
+
+// 作成可否
+int guild_created(int account_id,int guild_id)
+{
+ struct map_session_data *sd=map_id2sd(account_id);
+
+ if(sd==NULL)
+ return 0;
+ if(guild_id>0) {
+ struct guild *g;
+ sd->status.guild_id=guild_id;
+ sd->guild_sended=0;
+ if((g=numdb_search(guild_db,guild_id))!=NULL){
+ printf("guild: id already exists!\n");
+ exit(1);
+ }
+ clif_guild_created(sd,0);
+ if(battle_config.guild_emperium_check)
+ pc_delitem(sd,pc_search_inventory(sd,714),1,0); // エンペリウム消耗
+ } else {
+ clif_guild_created(sd,2); // 作成失敗(同名ギルド存在)
+ }
+ return 0;
+}
+
+// 情報要求
+int guild_request_info(int guild_id)
+{
+// if(battle_config.etc_log)
+// printf("guild_request_info\n");
+ return intif_guild_request_info(guild_id);
+}
+// イベント付き情報要求
+int guild_npc_request_info(int guild_id,const char *event)
+{
+ struct eventlist *ev;
+
+ if( guild_search(guild_id) ){
+ if(event && *event)
+ npc_event_do(event);
+ return 0;
+ }
+
+ if(event==NULL || *event==0)
+ return guild_request_info(guild_id);
+
+ ev=(struct eventlist *)aCalloc(1,sizeof(struct eventlist));
+ memcpy(ev->name,event,sizeof(ev->name));
+ ev->next=(struct eventlist *)numdb_search(guild_infoevent_db,guild_id);
+ numdb_insert(guild_infoevent_db,guild_id,ev);
+ return guild_request_info(guild_id);
+}
+
+// 所属キャラの確認
+int guild_check_member(const struct guild *g)
+{
+ int i;
+ struct map_session_data *sd;
+
+ nullpo_retr(0, g);
+
+ for(i=0;i<fd_max;i++){
+ if(session[i] && (sd=session[i]->session_data) && sd->state.auth){
+ if(sd->status.guild_id==g->guild_id){
+ int j,f=1;
+ for(j=0;j<MAX_GUILD;j++){ // データがあるか
+ if( g->member[j].account_id==sd->status.account_id &&
+ g->member[j].char_id==sd->status.char_id)
+ f=0;
+ }
+ if(f){
+ sd->status.guild_id=0;
+ sd->guild_sended=0;
+ sd->guild_emblem_id=0;
+ if(battle_config.error_log)
+ printf("guild: check_member %d[%s] is not member\n",sd->status.account_id,sd->status.name);
+ }
+ }
+ }
+ }
+ return 0;
+}
+// 情報所得失敗(そのIDのキャラを全部未所属にする)
+int guild_recv_noinfo(int guild_id)
+{
+ int i;
+ struct map_session_data *sd;
+ for(i=0;i<fd_max;i++){
+ if(session[i] && (sd=session[i]->session_data) && sd->state.auth){
+ if(sd->status.guild_id==guild_id)
+ sd->status.guild_id=0;
+ }
+ }
+ return 0;
+}
+// 情報所得
+int guild_recv_info(struct guild *sg)
+{
+ struct guild *g,before;
+ int i,bm,m;
+ struct eventlist *ev,*ev2;
+
+ nullpo_retr(0, sg);
+
+ if((g=numdb_search(guild_db,sg->guild_id))==NULL){
+ g=(struct guild *)aCalloc(1,sizeof(struct guild));
+ numdb_insert(guild_db,sg->guild_id,g);
+ before=*sg;
+
+ // 最初のロードなのでユーザーのチェックを行う
+ guild_check_member(sg);
+ }else
+ before=*g;
+ memcpy(g,sg,sizeof(struct guild));
+
+ for(i=bm=m=0;i<g->max_member;i++){ // sdの設定と人数の確認
+ if(g->member[i].account_id>0){
+ struct map_session_data *sd = map_id2sd(g->member[i].account_id);
+ g->member[i].sd=(sd!=NULL &&
+ sd->status.char_id==g->member[i].char_id &&
+ sd->status.guild_id==g->guild_id)? sd:NULL;
+ m++;
+ }else
+ g->member[i].sd=NULL;
+ if(before.member[i].account_id>0)
+ bm++;
+ }
+
+ for(i=0;i<g->max_member;i++){ // 情報の送信
+ struct map_session_data *sd = g->member[i].sd;
+ if( sd==NULL )
+ continue;
+
+ if( before.guild_lv!=g->guild_lv || bm!=m ||
+ before.max_member!=g->max_member ){
+ clif_guild_basicinfo(sd); // 基本情報送信
+ clif_guild_emblem(sd,g); // エンブレム送信
+ }
+
+ if(bm!=m){ // メンバー情報送信
+ clif_guild_memberlist(g->member[i].sd);
+ }
+
+ if( before.skill_point!=g->skill_point)
+ clif_guild_skillinfo(sd); // スキル情報送信
+
+ if( sd->guild_sended==0){ // 未送信なら所属情報も送る
+ clif_guild_belonginfo(sd,g);
+ clif_guild_notice(sd,g);
+ sd->guild_emblem_id=g->emblem_id;
+ sd->guild_sended=1;
+ }
+ }
+
+ // イベントの発生
+ if( (ev=numdb_search(guild_infoevent_db,sg->guild_id))!=NULL ){
+ numdb_erase(guild_infoevent_db,sg->guild_id);
+ for(;ev;ev2=ev->next,free(ev),ev=ev2){
+ npc_event_do(ev->name);
+ }
+ }
+
+ return 0;
+}
+
+
+// ギルドへの勧誘
+int guild_invite(struct map_session_data *sd,int account_id)
+{
+ struct map_session_data *tsd;
+ struct guild *g;
+ int i;
+
+ nullpo_retr(0, sd);
+
+ tsd= map_id2sd(account_id);
+ g=guild_search(sd->status.guild_id);
+
+ if(tsd==NULL || g==NULL)
+ return 0;
+ if(!battle_config.invite_request_check) {
+ if (tsd->party_invite>0 || tsd->trade_partner) { // 相手が取引中かどうか
+ clif_guild_inviteack(sd,0);
+ return 0;
+ }
+ }
+ if( tsd->status.guild_id>0 || tsd->guild_invite>0 ){ // 相手の所属確認
+ clif_guild_inviteack(sd,0);
+ return 0;
+ }
+
+ // 定員確認
+ for(i=0;i<g->max_member;i++)
+ if(g->member[i].account_id==0)
+ break;
+ if(i==g->max_member){
+ clif_guild_inviteack(sd,3);
+ return 0;
+ }
+
+ tsd->guild_invite=sd->status.guild_id;
+ tsd->guild_invite_account=sd->status.account_id;
+
+ clif_guild_invite(tsd,g);
+ return 0;
+}
+// ギルド勧誘への返答
+int guild_reply_invite(struct map_session_data *sd,int guild_id,int flag)
+{
+ struct map_session_data *tsd;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, tsd= map_id2sd( sd->guild_invite_account ));
+
+ if(sd->guild_invite!=guild_id) // 勧誘とギルドIDが違う
+ return 0;
+
+ if(flag==1){ // 承諾
+ struct guild_member m;
+ struct guild *g;
+ int i;
+
+ // 定員確認
+ if( (g=guild_search(tsd->status.guild_id))==NULL ){
+ sd->guild_invite=0;
+ sd->guild_invite_account=0;
+ return 0;
+ }
+ for(i=0;i<g->max_member;i++)
+ if(g->member[i].account_id==0)
+ break;
+ if(i==g->max_member){
+ sd->guild_invite=0;
+ sd->guild_invite_account=0;
+ clif_guild_inviteack(tsd,3);
+ return 0;
+ }
+
+
+ //inter鯖へ追加要求
+ guild_makemember(&m,sd);
+ intif_guild_addmember( sd->guild_invite, &m );
+ return 0;
+ }else{ // 拒否
+ sd->guild_invite=0;
+ sd->guild_invite_account=0;
+ if(tsd==NULL)
+ return 0;
+ clif_guild_inviteack(tsd,1);
+ }
+ return 0;
+}
+// ギルドメンバが追加された
+int guild_member_added(int guild_id,int account_id,int char_id,int flag)
+{
+ struct map_session_data *sd= map_id2sd(account_id),*sd2;
+ struct guild *g;
+
+ if( (g=guild_search(guild_id))==NULL )
+ return 0;
+
+ if((sd==NULL || sd->guild_invite==0) && flag==0){
+ // キャラ側に登録できなかったため脱退要求を出す
+ if(battle_config.error_log)
+ printf("guild: member added error %d is not online\n",account_id);
+ intif_guild_leave(guild_id,account_id,char_id,0,"**登録失敗**");
+ return 0;
+ }
+ sd->guild_invite=0;
+ sd->guild_invite_account=0;
+
+ sd2=map_id2sd(sd->guild_invite_account);
+
+ if(flag==1){ // 失敗
+ if( sd2!=NULL )
+ clif_guild_inviteack(sd2,3);
+ return 0;
+ }
+
+ // 成功
+ sd->guild_sended=0;
+ sd->status.guild_id=guild_id;
+
+ if( sd2!=NULL )
+ clif_guild_inviteack(sd2,2);
+
+ // いちおう競合確認
+ guild_check_conflict(sd);
+
+ return 0;
+}
+
+// ギルド脱退要求
+int guild_leave(struct map_session_data *sd,int guild_id,
+ int account_id,int char_id,const char *mes)
+{
+ struct guild *g;
+ int i;
+
+ nullpo_retr(0, sd);
+
+ g = guild_search(sd->status.guild_id);
+
+ if(g==NULL)
+ return 0;
+
+ if( sd->status.account_id!=account_id ||
+ sd->status.char_id!=char_id || sd->status.guild_id!=guild_id)
+ return 0;
+
+ for(i=0;i<g->max_member;i++){ // 所属しているか
+ if( g->member[i].account_id==sd->status.account_id &&
+ g->member[i].char_id==sd->status.char_id ){
+ intif_guild_leave(g->guild_id,sd->status.account_id,sd->status.char_id,0,mes);
+ return 0;
+ }
+ }
+ return 0;
+}
+// ギルド追放要求
+int guild_explusion(struct map_session_data *sd,int guild_id,
+ int account_id,int char_id,const char *mes)
+{
+ struct guild *g;
+ int i,ps;
+
+ nullpo_retr(0, sd);
+
+ g = guild_search(sd->status.guild_id);
+
+ if(g==NULL)
+ return 0;
+
+ if( sd->status.guild_id!=guild_id)
+ return 0;
+
+ if( (ps=guild_getposition(sd,g))<0 || !(g->position[ps].mode&0x0010) )
+ return 0; // 処罰権限無し
+
+ for(i=0;i<g->max_member;i++){ // 所属しているか
+ if( g->member[i].account_id==account_id &&
+ g->member[i].char_id==char_id ){
+ intif_guild_leave(g->guild_id,account_id,char_id,1,mes);
+ return 0;
+ }
+ }
+ return 0;
+}
+// ギルドメンバが脱退した
+int guild_member_leaved(int guild_id,int account_id,int char_id,int flag,
+ const char *name,const char *mes)
+{
+ struct map_session_data *sd=map_id2sd(account_id);
+ struct guild *g=guild_search(guild_id);
+ int i;
+
+ if(g!=NULL){
+ int i;
+ for(i=0;i<g->max_member;i++)
+ if( g->member[i].account_id==account_id &&
+ g->member[i].char_id==char_id ){
+ struct map_session_data *sd2=sd;
+ if(sd2==NULL)
+ sd2=guild_getavailablesd(g);
+ else
+ {
+ if(flag==0)
+ clif_guild_leave(sd2,name,mes);
+ else
+ clif_guild_explusion(sd2,name,mes,account_id);
+ }
+ g->member[i].account_id=0;
+ g->member[i].sd=NULL;
+ }
+ }
+ if(sd!=NULL && sd->status.guild_id==guild_id){
+ sd->status.guild_id=0;
+ sd->guild_emblem_id=0;
+ sd->guild_sended=0;
+ }
+
+ // メンバーリストを全員に再通知
+ for(i=0;i<g->max_member;i++){
+ if( g->member[i].sd!=NULL )
+ clif_guild_memberlist(g->member[i].sd);
+ }
+
+ return 0;
+}
+// ギルドメンバのオンライン状態/Lv更新送信
+int guild_send_memberinfoshort(struct map_session_data *sd,int online)
+{
+ struct guild *g;
+
+ nullpo_retr(0, sd);
+
+ if(sd->status.guild_id<=0)
+ return 0;
+ g=guild_search(sd->status.guild_id);
+ if(g==NULL)
+ return 0;
+
+ intif_guild_memberinfoshort(g->guild_id,
+ sd->status.account_id,sd->status.char_id,online,sd->status.base_level,sd->status.class);
+
+ if( !online ){ // ログアウトするならsdをクリアして終了
+ int i=guild_getindex(g,sd->status.account_id,sd->status.char_id);
+ if(i>=0)
+ g->member[i].sd=NULL;
+ return 0;
+ }
+
+ if( sd->guild_sended!=0 ) // ギルド初期送信データは送信済み
+ return 0;
+
+ // 競合確認
+ guild_check_conflict(sd);
+
+ // あるならギルド初期送信データ送信
+ if( (g=guild_search(sd->status.guild_id))!=NULL ){
+ guild_check_member(g); // 所属を確認する
+ if(sd->status.guild_id==g->guild_id){
+ clif_guild_belonginfo(sd,g);
+ clif_guild_notice(sd,g);
+ sd->guild_sended=1;
+ sd->guild_emblem_id=g->emblem_id;
+ }
+ }
+ return 0;
+}
+// ギルドメンバのオンライン状態/Lv更新通知
+int guild_recv_memberinfoshort(int guild_id,int account_id,int char_id,int online,int lv,int class)
+{
+ int i,alv,c,idx=0,om=0,oldonline=-1;
+ struct guild *g=guild_search(guild_id);
+ if(g==NULL)
+ return 0;
+ for(i=0,alv=0,c=0,om=0;i<g->max_member;i++){
+ struct guild_member *m=&g->member[i];
+ if(m->account_id==account_id && m->char_id==char_id ){
+ oldonline=m->online;
+ m->online=online;
+ m->lv=lv;
+ m->class=class;
+ idx=i;
+ }
+ if(m->account_id>0){
+ alv+=m->lv;
+ c++;
+ }
+ if(m->online)
+ om++;
+ }
+ if(idx==g->max_member){
+ if(battle_config.error_log)
+ printf("guild: not found member %d,%d on %d[%s]\n", account_id,char_id,guild_id,g->name);
+ return 0;
+ }
+ g->average_lv=alv/c;
+ g->connect_member=om;
+
+ if(oldonline!=online) // オンライン状態が変わったので通知
+ clif_guild_memberlogin_notice(g,idx,online);
+
+ for(i=0;i<g->max_member;i++){ // sd再設定
+ struct map_session_data *sd= map_id2sd(g->member[i].account_id);
+ g->member[i].sd=(sd!=NULL &&
+ sd->status.char_id==g->member[i].char_id &&
+ sd->status.guild_id==guild_id)?sd:NULL;
+ }
+
+ // ここにクライアントに送信処理が必要
+
+ return 0;
+}
+// ギルド会話送信
+int guild_send_message(struct map_session_data *sd,char *mes,int len)
+{
+ nullpo_retr(0, sd);
+
+ if(sd->status.guild_id==0)
+ return 0;
+ intif_guild_message(sd->status.guild_id,sd->status.account_id,mes,len);
+ return 0;
+}
+// ギルド会話受信
+int guild_recv_message(int guild_id,int account_id,char *mes,int len)
+{
+ struct guild *g;
+ if( (g=guild_search(guild_id))==NULL)
+ return 0;
+ clif_guild_message(g,account_id,mes,len);
+ return 0;
+}
+// ギルドメンバの役職変更
+int guild_change_memberposition(int guild_id,int account_id,int char_id,int idx)
+{
+ return intif_guild_change_memberinfo(
+ guild_id,account_id,char_id,GMI_POSITION,&idx,sizeof(idx));
+}
+// ギルドメンバの役職変更通知
+int guild_memberposition_changed(struct guild *g,int idx,int pos)
+{
+ nullpo_retr(0, g);
+
+ g->member[idx].position=pos;
+ clif_guild_memberpositionchanged(g,idx);
+ return 0;
+}
+// ギルド役職変更
+int guild_change_position(struct map_session_data *sd,int idx,
+ int mode,int exp_mode,const char *name)
+{
+ struct guild_position p;
+
+ nullpo_retr(0, sd);
+
+ if(exp_mode>battle_config.guild_exp_limit)
+ exp_mode=battle_config.guild_exp_limit;
+ if(exp_mode<0)exp_mode=0;
+ p.mode=mode;
+ p.exp_mode=exp_mode;
+ memcpy(p.name,name,24);
+ return intif_guild_position(sd->status.guild_id,idx,&p);
+}
+// ギルド役職変更通知
+int guild_position_changed(int guild_id,int idx,struct guild_position *p)
+{
+ struct guild *g=guild_search(guild_id);
+ if(g==NULL)
+ return 0;
+ memcpy(&g->position[idx],p,sizeof(struct guild_position));
+ clif_guild_positionchanged(g,idx);
+ return 0;
+}
+// ギルド告知変更
+int guild_change_notice(struct map_session_data *sd,int guild_id,const char *mes1,const char *mes2)
+{
+ nullpo_retr(0, sd);
+
+ if(guild_id!=sd->status.guild_id)
+ return 0;
+ return intif_guild_notice(guild_id,mes1,mes2);
+}
+// ギルド告知変更通知
+int guild_notice_changed(int guild_id,const char *mes1,const char *mes2)
+{
+ int i;
+ struct map_session_data *sd;
+ struct guild *g=guild_search(guild_id);
+ if(g==NULL)
+ return 0;
+
+ memcpy(g->mes1,mes1,60);
+ memcpy(g->mes2,mes2,120);
+
+ for(i=0;i<g->max_member;i++){
+ if((sd=g->member[i].sd)!=NULL)
+ clif_guild_notice(sd,g);
+ }
+ return 0;
+}
+// ギルドエンブレム変更
+int guild_change_emblem(struct map_session_data *sd,int len,const char *data)
+{
+ nullpo_retr(0, sd);
+
+ return intif_guild_emblem(sd->status.guild_id,len,data);
+}
+// ギルドエンブレム変更通知
+int guild_emblem_changed(int len,int guild_id,int emblem_id,const char *data)
+{
+ int i;
+ struct map_session_data *sd;
+ struct guild *g=guild_search(guild_id);
+ if(g==NULL)
+ return 0;
+
+ memcpy(g->emblem_data,data,len);
+ g->emblem_len=len;
+ g->emblem_id=emblem_id;
+
+ for(i=0;i<g->max_member;i++){
+ if((sd=g->member[i].sd)!=NULL){
+ sd->guild_emblem_id=emblem_id;
+ clif_guild_belonginfo(sd,g);
+ clif_guild_emblem(sd,g);
+ }
+ }
+ return 0;
+}
+
+// ギルドのEXP上納
+int guild_payexp(struct map_session_data *sd,int exp)
+{
+ struct guild *g;
+ struct guild_expcache *c;
+ int per,exp2;
+
+ nullpo_retr(0, sd);
+
+ if(sd->status.guild_id==0 || (g=guild_search(sd->status.guild_id))==NULL )
+ return 0;
+ if( (per=g->position[guild_getposition(sd,g)].exp_mode)<=0 )
+ return 0;
+ if( per>100 )per=100;
+
+ if( (exp2=exp*per/100)<=0 )
+ return 0;
+
+ if( (c=numdb_search(guild_expcache_db,sd->status.char_id))==NULL ){
+ c=(struct guild_expcache *)aCalloc(1,sizeof(struct guild_expcache));
+ c->guild_id=sd->status.guild_id;
+ c->account_id=sd->status.account_id;
+ c->char_id=sd->status.char_id;
+ c->exp=exp2;
+ numdb_insert(guild_expcache_db,c->char_id,c);
+ }else{
+ c->exp+=exp2;
+ }
+ return exp2;
+}
+
+// スキルポイント割り振り
+int guild_skillup(struct map_session_data *sd,int skill_num,int flag)
+{
+ struct guild *g;
+ int idx;
+
+ nullpo_retr(0, sd);
+
+ if(sd->status.guild_id==0 || (g=guild_search(sd->status.guild_id))==NULL)
+ return 0;
+ if(strcmp(sd->status.name,g->master))
+ return 0;
+
+ if( (g->skill_point>0 || flag&1) &&
+ g->skill[(idx=skill_num-10000)].id!=0 &&
+ g->skill[idx].lv < guild_skill_get_max(skill_num) ){
+ intif_guild_skillup(g->guild_id,skill_num,sd->status.account_id,flag);
+ }
+ return 0;
+}
+// スキルポイント割り振り通知
+int guild_skillupack(int guild_id,int skill_num,int account_id)
+{
+ struct map_session_data *sd=map_id2sd(account_id);
+ struct guild *g=guild_search(guild_id);
+ int i;
+ if(g==NULL)
+ return 0;
+ if(sd!=NULL)
+ clif_guild_skillup(sd,skill_num,g->skill[skill_num-10000].lv);
+ // 全員に通知
+ for(i=0;i<g->max_member;i++)
+ if((sd=g->member[i].sd)!=NULL)
+ clif_guild_skillinfo(sd);
+ return 0;
+}
+
+// ギルド同盟数所得
+int guild_get_alliance_count(struct guild *g,int flag)
+{
+ int i,c;
+
+ nullpo_retr(0, g);
+
+ for(i=c=0;i<MAX_GUILDALLIANCE;i++){
+ if( g->alliance[i].guild_id>0 &&
+ g->alliance[i].opposition==flag )
+ c++;
+ }
+ return c;
+}
+// ギルド同盟要求
+int guild_reqalliance(struct map_session_data *sd,int account_id)
+{
+ struct map_session_data *tsd= map_id2sd(account_id);
+ struct guild *g[2];
+ int i;
+
+ if(agit_flag) { // Disable alliance creation during woe [Valaris]
+ clif_displaymessage(sd->fd,"Alliances cannot be made during Guild Wars!");
+ return 0;
+ } // end addition [Valaris]
+
+
+ nullpo_retr(0, sd);
+
+ if(tsd==NULL || tsd->status.guild_id<=0)
+ return 0;
+
+ g[0]=guild_search(sd->status.guild_id);
+ g[1]=guild_search(tsd->status.guild_id);
+
+ if(g[0]==NULL || g[1]==NULL)
+ return 0;
+
+ if( guild_get_alliance_count(g[0],0)>3 ) // 同盟数確認
+ clif_guild_allianceack(sd,4);
+ if( guild_get_alliance_count(g[1],0)>3 )
+ clif_guild_allianceack(sd,3);
+
+ if( tsd->guild_alliance>0 ){ // 相手が同盟要請状態かどうか確認
+ clif_guild_allianceack(sd,1);
+ return 0;
+ }
+
+ for(i=0;i<MAX_GUILDALLIANCE;i++){ // すでに同盟状態か確認
+ if( g[0]->alliance[i].guild_id==tsd->status.guild_id &&
+ g[0]->alliance[i].opposition==0){
+ clif_guild_allianceack(sd,0);
+ return 0;
+ }
+ }
+
+ tsd->guild_alliance=sd->status.guild_id;
+ tsd->guild_alliance_account=sd->status.account_id;
+
+ clif_guild_reqalliance(tsd,sd->status.account_id,g[0]->name);
+ return 0;
+}
+// ギルド勧誘への返答
+int guild_reply_reqalliance(struct map_session_data *sd,int account_id,int flag)
+{
+ struct map_session_data *tsd;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, tsd= map_id2sd( account_id ));
+
+ if(sd->guild_alliance!=tsd->status.guild_id) // 勧誘とギルドIDが違う
+ return 0;
+
+ if(flag==1){ // 承諾
+ int i;
+
+ struct guild *g; // 同盟数再確認
+ if( (g=guild_search(sd->status.guild_id))==NULL ||
+ guild_get_alliance_count(g,0)>3 ){
+ clif_guild_allianceack(sd,4);
+ clif_guild_allianceack(tsd,3);
+ return 0;
+ }
+ if( (g=guild_search(tsd->status.guild_id))==NULL ||
+ guild_get_alliance_count(g,0)>3 ){
+ clif_guild_allianceack(sd,3);
+ clif_guild_allianceack(tsd,4);
+ return 0;
+ }
+
+ // 敵対関係なら敵対を止める
+ if((g=guild_search(sd->status.guild_id)) == NULL)
+ return 0;
+ for(i=0;i<MAX_GUILDALLIANCE;i++){
+ if( g->alliance[i].guild_id==tsd->status.guild_id &&
+ g->alliance[i].opposition==1)
+ intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id,
+ sd->status.account_id,tsd->status.account_id,9 );
+ }
+ if((g=guild_search(tsd->status.guild_id)) == NULL)
+ return 0;
+ for(i=0;i<MAX_GUILDALLIANCE;i++){
+ if( g->alliance[i].guild_id==sd->status.guild_id &&
+ g->alliance[i].opposition==1)
+ intif_guild_alliance( tsd->status.guild_id,sd->status.guild_id,
+ tsd->status.account_id,sd->status.account_id,9 );
+ }
+
+ // inter鯖へ同盟要請
+ intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id,
+ sd->status.account_id,tsd->status.account_id,0 );
+ return 0;
+ }else{ // 拒否
+ sd->guild_alliance=0;
+ sd->guild_alliance_account=0;
+ if(tsd!=NULL)
+ clif_guild_allianceack(tsd,3);
+ }
+ return 0;
+}
+// ギルド関係解消
+int guild_delalliance(struct map_session_data *sd,int guild_id,int flag)
+{
+ if(agit_flag) { // Disable alliance breaking during woe [Valaris]
+ clif_displaymessage(sd->fd,"Alliances cannot be broken during Guild Wars!");
+ return 0;
+ } // end addition [Valaris]
+
+ nullpo_retr(0, sd);
+
+ intif_guild_alliance( sd->status.guild_id,guild_id,
+ sd->status.account_id,0,flag|8 );
+ return 0;
+}
+// ギルド敵対
+int guild_opposition(struct map_session_data *sd,int char_id)
+{
+ struct map_session_data *tsd=map_id2sd(char_id);
+ struct guild *g;
+ int i;
+
+ nullpo_retr(0, sd);
+
+ g=guild_search(sd->status.guild_id);
+ if(g==NULL || tsd==NULL)
+ return 0;
+
+ if( guild_get_alliance_count(g,1)>3 ) // 敵対数確認
+ clif_guild_oppositionack(sd,1);
+
+ for(i=0;i<MAX_GUILDALLIANCE;i++){ // すでに関係を持っているか確認
+ if(g->alliance[i].guild_id==tsd->status.guild_id){
+ if(g->alliance[i].opposition==1){ // すでに敵対
+ clif_guild_oppositionack(sd,2);
+ return 0;
+ }else // 同盟破棄
+ intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id,
+ sd->status.account_id,tsd->status.account_id,8 );
+ }
+ }
+
+ // inter鯖に敵対要請
+ intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id,
+ sd->status.account_id,tsd->status.account_id,1 );
+ return 0;
+}
+// ギルド同盟/敵対通知
+int guild_allianceack(int guild_id1,int guild_id2,int account_id1,int account_id2,
+ int flag,const char *name1,const char *name2)
+{
+ struct guild *g[2];
+ int guild_id[2]={guild_id1,guild_id2};
+ const char *guild_name[2]={name1,name2};
+ struct map_session_data *sd[2]={map_id2sd(account_id1),map_id2sd(account_id2)};
+ int j,i;
+
+ g[0]=guild_search(guild_id1);
+ g[1]=guild_search(guild_id2);
+
+ if(sd[0]!=NULL && (flag&0x0f)==0){
+ sd[0]->guild_alliance=0;
+ sd[0]->guild_alliance_account=0;
+ }
+
+ if(flag&0x70){ // 失敗
+ for(i=0;i<2-(flag&1);i++)
+ if( sd[i]!=NULL )
+ clif_guild_allianceack(sd[i],((flag>>4)==i+1)?3:4);
+ return 0;
+ }
+// if(battle_config.etc_log)
+// printf("guild alliance_ack %d %d %d %d %d %s %s\n",guild_id1,guild_id2,account_id1,account_id2,flag,name1,name2);
+
+ if(!(flag&0x08)){ // 関係追加
+ for(i=0;i<2-(flag&1);i++)
+ if(g[i]!=NULL)
+ for(j=0;j<MAX_GUILDALLIANCE;j++)
+ if(g[i]->alliance[j].guild_id==0){
+ g[i]->alliance[j].guild_id=guild_id[1-i];
+ memcpy(g[i]->alliance[j].name,guild_name[1-i],24);
+ g[i]->alliance[j].opposition=flag&1;
+ break;
+ }
+ }else{ // 関係解消
+ for(i=0;i<2-(flag&1);i++){
+ if(g[i]!=NULL)
+ for(j=0;j<MAX_GUILDALLIANCE;j++)
+ if( g[i]->alliance[j].guild_id==guild_id[1-i] &&
+ g[i]->alliance[j].opposition==(flag&1)){
+ g[i]->alliance[j].guild_id=0;
+ break;
+ }
+ if( sd[i]!=NULL ) // 解消通知
+ clif_guild_delalliance(sd[i],guild_id[1-i],(flag&1));
+ }
+ }
+
+ if((flag&0x0f)==0){ // 同盟通知
+ if( sd[1]!=NULL )
+ clif_guild_allianceack(sd[1],2);
+ }else if((flag&0x0f)==1){ // 敵対通知
+ if( sd[0]!=NULL )
+ clif_guild_oppositionack(sd[0],0);
+ }
+
+
+ for(i=0;i<2-(flag&1);i++){ // 同盟/敵対リストの再送信
+ struct map_session_data *sd;
+ if(g[i]!=NULL)
+ for(j=0;j<g[i]->max_member;j++)
+ if((sd=g[i]->member[j].sd)!=NULL)
+ clif_guild_allianceinfo(sd);
+ }
+ return 0;
+}
+// ギルド解散通知用
+int guild_broken_sub(void *key,void *data,va_list ap)
+{
+ struct guild *g=(struct guild *)data;
+ int guild_id=va_arg(ap,int);
+ int i,j;
+ struct map_session_data *sd=NULL;
+
+ nullpo_retr(0, g);
+
+ for(i=0;i<MAX_GUILDALLIANCE;i++){ // 関係を破棄
+ if(g->alliance[i].guild_id==guild_id){
+ for(j=0;j<g->max_member;j++)
+ if( (sd=g->member[j].sd)!=NULL )
+ clif_guild_delalliance(sd,guild_id,g->alliance[i].opposition);
+ g->alliance[i].guild_id=0;
+ }
+ }
+ return 0;
+}
+// ギルド解散通知
+int guild_broken(int guild_id,int flag)
+{
+ struct guild *g=guild_search(guild_id);
+ struct map_session_data *sd;
+ int i;
+ if(flag!=0 || g==NULL)
+ return 0;
+
+ for(i=0;i<g->max_member;i++){ // ギルド解散を通知
+ if((sd=g->member[i].sd)!=NULL){
+ if(sd->state.storage_flag)
+ storage_guild_storage_quit(sd,1);
+ sd->status.guild_id=0;
+ sd->guild_sended=0;
+ clif_guild_broken(g->member[i].sd,0);
+ }
+ }
+
+ numdb_foreach(guild_db,guild_broken_sub,guild_id);
+ numdb_erase(guild_db,guild_id);
+ guild_storage_delete(guild_id);
+ free(g);
+ return 0;
+}
+
+// ギルド解散
+int guild_break(struct map_session_data *sd,char *name)
+{
+ struct guild *g;
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if( (g=guild_search(sd->status.guild_id))==NULL )
+ return 0;
+ if(strcmp(g->name,name)!=0)
+ return 0;
+ if(strcmp(sd->status.name,g->master)!=0)
+ return 0;
+ for(i=0;i<g->max_member;i++){
+ if( g->member[i].account_id>0 && (
+ g->member[i].account_id!=sd->status.account_id ||
+ g->member[i].char_id!=sd->status.char_id ))
+ break;
+ }
+ if(i<g->max_member){
+ clif_guild_broken(sd,2);
+ return 0;
+ }
+
+ intif_guild_break(g->guild_id);
+ return 0;
+}
+
+// ギルド城データ要求
+int guild_castledataload(int castle_id,int index)
+{
+ return intif_guild_castle_dataload(castle_id,index);
+}
+// ギルド城情報所得時イベント追加
+int guild_addcastleinfoevent(int castle_id,int index,const char *name)
+{
+ struct eventlist *ev;
+ int code=castle_id|(index<<16);
+
+ if( name==NULL || *name==0 )
+ return 0;
+
+ ev=(struct eventlist *)aCalloc(1,sizeof(struct eventlist));
+ memcpy(ev->name,name,sizeof(ev->name));
+ ev->next=numdb_search(guild_castleinfoevent_db,code);
+ numdb_insert(guild_castleinfoevent_db,code,ev);
+ return 0;
+}
+
+// ギルド城データ要求返信
+int guild_castledataloadack(int castle_id,int index,int value)
+{
+ struct guild_castle *gc=guild_castle_search(castle_id);
+ int code=castle_id|(index<<16);
+ struct eventlist *ev,*ev2;
+
+ if(gc==NULL){
+ return 0;
+ }
+ switch(index){
+ case 1: gc->guild_id = value; break;
+ case 2: gc->economy = value; break;
+ case 3: gc->defense = value; break;
+ case 4: gc->triggerE = value; break;
+ case 5: gc->triggerD = value; break;
+ case 6: gc->nextTime = value; break;
+ case 7: gc->payTime = value; break;
+ case 8: gc->createTime = value; break;
+ case 9: gc->visibleC = value; break;
+ case 10: gc->visibleG0 = value; break;
+ case 11: gc->visibleG1 = value; break;
+ case 12: gc->visibleG2 = value; break;
+ case 13: gc->visibleG3 = value; break;
+ case 14: gc->visibleG4 = value; break;
+ case 15: gc->visibleG5 = value; break;
+ case 16: gc->visibleG6 = value; break;
+ case 17: gc->visibleG7 = value; break;
+ case 18: gc->Ghp0 = value; break; // guardian HP [Valaris]
+ case 19: gc->Ghp1 = value; break;
+ case 20: gc->Ghp2 = value; break;
+ case 21: gc->Ghp3 = value; break;
+ case 22: gc->Ghp4 = value; break;
+ case 23: gc->Ghp5 = value; break;
+ case 24: gc->Ghp6 = value; break;
+ case 25: gc->Ghp7 = value; break; // end additions [Valaris]
+ default:
+ printf("guild_castledataloadack ERROR!! (Not found index=%d)\n", index);
+ return 0;
+ }
+ if( (ev=numdb_search(guild_castleinfoevent_db,code))!=NULL ){
+ numdb_erase(guild_castleinfoevent_db,code);
+ for(;ev;ev2=ev->next,free(ev),ev=ev2){
+ npc_event_do(ev->name);
+ }
+ }
+ return 1;
+}
+// ギルド城データ変更要求
+int guild_castledatasave(int castle_id,int index,int value)
+{
+ return intif_guild_castle_datasave(castle_id,index,value);
+}
+
+// ギルド城データ変更通知
+int guild_castledatasaveack(int castle_id,int index,int value)
+{
+ struct guild_castle *gc=guild_castle_search(castle_id);
+ if(gc==NULL){
+ return 0;
+ }
+ switch(index){
+ case 1: gc->guild_id = value; break;
+ case 2: gc->economy = value; break;
+ case 3: gc->defense = value; break;
+ case 4: gc->triggerE = value; break;
+ case 5: gc->triggerD = value; break;
+ case 6: gc->nextTime = value; break;
+ case 7: gc->payTime = value; break;
+ case 8: gc->createTime = value; break;
+ case 9: gc->visibleC = value; break;
+ case 10: gc->visibleG0 = value; break;
+ case 11: gc->visibleG1 = value; break;
+ case 12: gc->visibleG2 = value; break;
+ case 13: gc->visibleG3 = value; break;
+ case 14: gc->visibleG4 = value; break;
+ case 15: gc->visibleG5 = value; break;
+ case 16: gc->visibleG6 = value; break;
+ case 17: gc->visibleG7 = value; break;
+ case 18: gc->Ghp0 = value; break; // guardian HP [Valaris]
+ case 19: gc->Ghp1 = value; break;
+ case 20: gc->Ghp2 = value; break;
+ case 21: gc->Ghp3 = value; break;
+ case 22: gc->Ghp4 = value; break;
+ case 23: gc->Ghp5 = value; break;
+ case 24: gc->Ghp6 = value; break;
+ case 25: gc->Ghp7 = value; break; // end additions [Valaris]
+ default:
+ printf("guild_castledatasaveack ERROR!! (Not found index=%d)\n", index);
+ return 0;
+ }
+ return 1;
+}
+
+// ギルドデータ一括受信(初期化時)
+int guild_castlealldataload(int len,struct guild_castle *gc)
+{
+ int i;
+ int n = (len-4) / sizeof(struct guild_castle), ev = -1;
+
+ nullpo_retr(0, gc);
+
+ // イベント付きで要求するデータ位置を探す(最後の占拠データ)
+ for(i = 0; i < n; i++) {
+ if ((gc + i)->guild_id)
+ ev = i;
+ }
+
+ // 城データ格納とギルド情報要求
+ for(i = 0; i < n; i++, gc++) {
+ struct guild_castle *c = guild_castle_search(gc->castle_id);
+ if (!c) {
+ printf("guild_castlealldataload ??\n");
+ continue;
+ }
+ memcpy(&c->guild_id,&gc->guild_id,
+ sizeof(struct guild_castle) - ((int)&c->guild_id - (int)c) );
+ if( c->guild_id ){
+ if(i!=ev)
+ guild_request_info(c->guild_id);
+ else
+ guild_npc_request_info(c->guild_id, "::OnAgitInit");
+ }
+ }
+ if (ev == -1)
+ npc_event_doall("OnAgitInit");
+ return 0;
+}
+
+int guild_agit_start(void)
+{ // Run All NPC_Event[OnAgitStart]
+ int c = npc_event_doall("OnAgitStart");
+ printf("NPC_Event:[OnAgitStart] Run (%d) Events by @AgitStart.\n",c);
+ return 0;
+}
+
+int guild_agit_end(void)
+{ // Run All NPC_Event[OnAgitEnd]
+ int c = npc_event_doall("OnAgitEnd");
+ printf("NPC_Event:[OnAgitEnd] Run (%d) Events by @AgitEnd.\n",c);
+ return 0;
+}
+
+int guild_gvg_eliminate_timer(int tid,unsigned int tick,int id,int data)
+{ // Run One NPC_Event[OnAgitEliminate]
+ size_t len = strlen((const char*)data);
+ char *evname=(char*)aCalloc(len + 4,sizeof(char));
+ int c=0;
+
+ if(!agit_flag) return 0; // Agit already End
+ memcpy(evname,(const char *)data,len - 5);
+ strcpy(evname + len - 5,"Eliminate");
+ c = npc_event_do(evname);
+ printf("NPC_Event:[%s] Run (%d) Events.\n",evname,c);
+ return 0;
+}
+
+int guild_agit_break(struct mob_data *md)
+{ // Run One NPC_Event[OnAgitBreak]
+ char *evname;
+
+ nullpo_retr(0, md);
+
+ evname=(char *)aCalloc(strlen(md->npc_event) + 1, sizeof(char));
+
+ strcpy(evname,md->npc_event);
+// Now By User to Run [OnAgitBreak] NPC Event...
+// It's a little impossible to null point with player disconnect in this!
+// But Script will be stop, so nothing...
+// Maybe will be changed in the futher..
+// int c = npc_event_do(evname);
+ if(!agit_flag) return 0; // Agit already End
+ add_timer(gettick()+battle_config.gvg_eliminate_time,guild_gvg_eliminate_timer,md->bl.m,(int)evname);
+ return 0;
+}
+
+// [MouseJstr]
+// How many castles does this guild have?
+int guild_checkcastles(struct guild *g) {
+ int i,nb_cas=0, id,cas_id=0;
+ struct guild_castle *gc;
+ id=g->guild_id;
+ for(i=0;i<MAX_GUILDCASTLE;i++){
+ gc=guild_castle_search(i);
+ cas_id=gc->guild_id;
+ if(g->guild_id==cas_id)
+ nb_cas=nb_cas+1;
+ } //end for
+ return nb_cas;
+}
+
+// [MouseJstr]
+// is this guild allied with this castle?
+int guild_isallied(struct guild *g, struct guild_castle *gc)
+{
+ int i;
+
+ nullpo_retr(0, g);
+
+ if(g->guild_id == gc->guild_id)
+ return 1;
+
+ if (gc->guild_id == 0)
+ return 0;
+
+
+ for(i=0;i<MAX_GUILDALLIANCE;i++)
+ if(g->alliance[i].guild_id == gc->guild_id) {
+ if(g->alliance[i].opposition == 0)
+ return 1;
+ else
+ return 0;
+ }
+
+ return 0;
+}
+
+static int guild_db_final(void *key,void *data,va_list ap)
+{
+ struct guild *g=data;
+
+ free(g);
+
+ return 0;
+}
+static int castle_db_final(void *key,void *data,va_list ap)
+{
+ struct guild_castle *gc=data;
+
+ free(gc);
+
+ return 0;
+}
+static int guild_expcache_db_final(void *key,void *data,va_list ap)
+{
+ struct guild_expcache *c=data;
+
+ free(c);
+
+ return 0;
+}
+static int guild_infoevent_db_final(void *key,void *data,va_list ap)
+{
+ struct eventlist *ev=data;
+
+ free(ev);
+
+ return 0;
+}
+void do_final_guild(void)
+{
+ if(guild_db)
+ numdb_final(guild_db,guild_db_final);
+ if(castle_db)
+ numdb_final(castle_db,castle_db_final);
+ if(guild_expcache_db)
+ numdb_final(guild_expcache_db,guild_expcache_db_final);
+ if(guild_infoevent_db)
+ numdb_final(guild_infoevent_db,guild_infoevent_db_final);
+ if(guild_castleinfoevent_db)
+ numdb_final(guild_castleinfoevent_db,guild_infoevent_db_final);
+}
diff --git a/src/map/guild.h b/src/map/guild.h
new file mode 100644
index 000000000..46842464f
--- /dev/null
+++ b/src/map/guild.h
@@ -0,0 +1,87 @@
+// $Id: guild.h,v 1.4 2004/09/25 05:32:18 MouseJstr Exp $
+#ifndef _GUILD_H_
+#define _GUILD_H_
+
+struct map_session_data;
+struct mob_data;
+struct guild;
+struct guild_member;
+struct guild_position;
+struct guild_castle;
+
+int guild_skill_get_inf(int id);
+int guild_skill_get_sp(int id,int lv);
+int guild_skill_get_range(int id);
+int guild_skill_get_max(int id);
+
+int guild_checkskill(struct guild *g,int id);
+int guild_checkcastles(struct guild *g); // [MouseJstr]
+int guild_isallied(struct guild *g, struct guild_castle *gc);
+
+void do_init_guild(void);
+struct guild *guild_search(int guild_id);
+struct guild *guild_searchname(char *str);
+struct guild_castle *guild_castle_search(int gcid);
+
+struct guild_castle *guild_mapname2gc(char *mapname);
+
+struct map_session_data *guild_getavailablesd(struct guild *g);
+int guild_getindex(struct guild *g,int account_id,int char_id);
+int guild_getposition(struct map_session_data *sd,struct guild *g);
+int guild_payexp(struct map_session_data *sd,int exp);
+
+int guild_create(struct map_session_data *sd,char *name);
+int guild_created(int account_id,int guild_id);
+int guild_request_info(int guild_id);
+int guild_recv_noinfo(int guild_id);
+int guild_recv_info(struct guild *sg);
+int guild_npc_request_info(int guild_id,const char *ev);
+int guild_invite(struct map_session_data *sd,int account_id);
+int guild_reply_invite(struct map_session_data *sd,int guild_id,int flag);
+int guild_member_added(int guild_id,int account_id,int char_id,int flag);
+int guild_leave(struct map_session_data *sd,int guild_id,
+ int account_id,int char_id,const char *mes);
+int guild_member_leaved(int guild_id,int account_id,int char_id,int flag,
+ const char *name,const char *mes);
+int guild_explusion(struct map_session_data *sd,int guild_id,
+ int account_id,int char_id,const char *mes);
+int guild_skillup(struct map_session_data *sd,int skill_num,int flag);
+int guild_reqalliance(struct map_session_data *sd,int account_id);
+int guild_reply_reqalliance(struct map_session_data *sd,int account_id,int flag);
+int guild_alliance(int guild_id1,int guild_id2,int account_id1,int account_id2);
+int guild_allianceack(int guild_id1,int guild_id2,int account_id1,int account_id2,
+ int flag,const char *name1,const char *name2);
+int guild_delalliance(struct map_session_data *sd,int guild_id,int flag);
+int guild_opposition(struct map_session_data *sd,int char_id);
+
+int guild_send_memberinfoshort(struct map_session_data *sd,int online);
+int guild_recv_memberinfoshort(int guild_id,int account_id,int char_id,int online,int lv,int class);
+int guild_change_memberposition(int guild_id,int account_id,int char_id,int idx);
+int guild_memberposition_changed(struct guild *g,int idx,int pos);
+int guild_change_position(struct map_session_data *sd,int idx,
+ int mode,int exp_mode,const char *name);
+int guild_position_changed(int guild_id,int idx,struct guild_position *p);
+int guild_change_notice(struct map_session_data *sd,int guild_id,const char *mes1,const char *mes2);
+int guild_notice_changed(int guild_id,const char *mes1,const char *mes2);
+int guild_change_emblem(struct map_session_data *sd,int len,const char *data);
+int guild_emblem_changed(int len,int guild_id,int emblem_id,const char *data);
+int guild_send_message(struct map_session_data *sd,char *mes,int len);
+int guild_recv_message(int guild_id,int account_id,char *mes,int len);
+int guild_skillupack(int guild_id,int skill_num,int account_id);
+int guild_break(struct map_session_data *sd,char *name);
+int guild_broken(int guild_id,int flag);
+
+int guild_addcastleinfoevent(int castle_id,int index,const char *name);
+int guild_castledataload(int castle_id,int index);
+int guild_castledataloadack(int castle_id,int index,int value);
+int guild_castledatasave(int castle_id,int index,int value);
+int guild_castledatasaveack(int castle_id,int index,int value);
+int guild_castlealldataload(int len,struct guild_castle *gc);
+
+int guild_agit_start(void);
+int guild_agit_end(void);
+int guild_agit_break(struct mob_data *md);
+
+void do_final_guild(void);
+
+#endif
diff --git a/src/map/intif.c b/src/map/intif.c
new file mode 100644
index 000000000..a2bdbe7ee
--- /dev/null
+++ b/src/map/intif.c
@@ -0,0 +1,1119 @@
+// $Id: intif.c,v 1.2 2004/09/25 05:32:18 MouseJstr Exp $
+#include <sys/types.h>
+#ifdef _WIN32
+#include <winsock.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef _WIN32
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#endif
+#include <signal.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "socket.h"
+#include "timer.h"
+#include "map.h"
+#include "battle.h"
+#include "chrif.h"
+#include "clif.h"
+#include "pc.h"
+#include "intif.h"
+#include "storage.h"
+#include "party.h"
+#include "guild.h"
+#include "pet.h"
+#include "nullpo.h"
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+static const int packet_len_table[]={
+ -1,-1,27,-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -1, 7, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0,
+ 35,-1,11,15, 34,29, 7,-1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 10,-1,15, 0, 79,19, 7,-1, 0,-1,-1,-1, 14,67,186,-1,
+ 9, 9,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 11,-1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+extern int char_fd; // inter serverのfdはchar_fdを使う
+#define inter_fd (char_fd) // エイリアス
+
+//-----------------------------------------------------------------
+// inter serverへの送信
+
+// pet
+int intif_create_pet(int account_id,int char_id,short pet_class,short pet_lv,short pet_egg_id,
+ short pet_equip,short intimate,short hungry,char rename_flag,char incuvate,char *pet_name)
+{
+ WFIFOW(inter_fd,0) = 0x3080;
+ WFIFOL(inter_fd,2) = account_id;
+ WFIFOL(inter_fd,6) = char_id;
+ WFIFOW(inter_fd,10) = pet_class;
+ WFIFOW(inter_fd,12) = pet_lv;
+ WFIFOW(inter_fd,14) = pet_egg_id;
+ WFIFOW(inter_fd,16) = pet_equip;
+ WFIFOW(inter_fd,18) = intimate;
+ WFIFOW(inter_fd,20) = hungry;
+ WFIFOB(inter_fd,22) = rename_flag;
+ WFIFOB(inter_fd,23) = incuvate;
+ memcpy(WFIFOP(inter_fd,24),pet_name,24);
+ WFIFOSET(inter_fd,48);
+
+ return 0;
+}
+
+int intif_request_petdata(int account_id,int char_id,int pet_id)
+{
+ WFIFOW(inter_fd,0) = 0x3081;
+ WFIFOL(inter_fd,2) = account_id;
+ WFIFOL(inter_fd,6) = char_id;
+ WFIFOL(inter_fd,10) = pet_id;
+ WFIFOSET(inter_fd,14);
+
+ return 0;
+}
+
+int intif_save_petdata(int account_id,struct s_pet *p)
+{
+ WFIFOW(inter_fd,0) = 0x3082;
+ WFIFOW(inter_fd,2) = sizeof(struct s_pet) + 8;
+ WFIFOL(inter_fd,4) = account_id;
+ memcpy(WFIFOP(inter_fd,8),p,sizeof(struct s_pet));
+ WFIFOSET(inter_fd,WFIFOW(inter_fd,2));
+
+ return 0;
+}
+
+int intif_delete_petdata(int pet_id)
+{
+ WFIFOW(inter_fd,0) = 0x3083;
+ WFIFOL(inter_fd,2) = pet_id;
+ WFIFOSET(inter_fd,6);
+
+ return 0;
+}
+
+// GMメッセージを送信
+int intif_GMmessage(char* mes,int len,int flag)
+{
+ int lp = (flag&0x10) ? 8 : 4;
+ WFIFOW(inter_fd,0) = 0x3000;
+ WFIFOW(inter_fd,2) = lp + len;
+ WFIFOL(inter_fd,4) = 0x65756c62;
+ memcpy(WFIFOP(inter_fd,lp), mes, len);
+ WFIFOSET(inter_fd, WFIFOW(inter_fd,2));
+
+ return 0;
+}
+
+// The transmission of Wisp/Page to inter-server (player not found on this server)
+int intif_wis_message(struct map_session_data *sd, char *nick, char *mes, int mes_len) {
+ nullpo_retr(0, sd);
+
+ WFIFOW(inter_fd,0) = 0x3001;
+ WFIFOW(inter_fd,2) = mes_len + 52;
+ memcpy(WFIFOP(inter_fd,4), sd->status.name, 24);
+ memcpy(WFIFOP(inter_fd,28), nick, 24);
+ memcpy(WFIFOP(inter_fd,52), mes, mes_len);
+ WFIFOSET(inter_fd, WFIFOW(inter_fd,2));
+
+ if (battle_config.etc_log)
+ printf("intif_wis_message from %s to %s (message: '%s')\n", sd->status.name, nick, mes);
+
+ return 0;
+}
+
+// The reply of Wisp/page
+int intif_wis_replay(int id, int flag) {
+ WFIFOW(inter_fd,0) = 0x3002;
+ WFIFOL(inter_fd,2) = id;
+ WFIFOB(inter_fd,6) = flag; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
+ WFIFOSET(inter_fd,7);
+
+ if (battle_config.etc_log)
+ printf("intif_wis_replay: id: %d, flag:%d\n", id, flag);
+
+ return 0;
+}
+
+// The transmission of GM only Wisp/Page from server to inter-server
+int intif_wis_message_to_gm(char *Wisp_name, int min_gm_level, char *mes, int mes_len) {
+ WFIFOW(inter_fd,0) = 0x3003;
+ WFIFOW(inter_fd,2) = mes_len + 30;
+ memcpy(WFIFOP(inter_fd,4), Wisp_name, 24);
+ WFIFOW(inter_fd,28) = (short)min_gm_level;
+ memcpy(WFIFOP(inter_fd,30), mes, mes_len);
+ WFIFOSET(inter_fd, WFIFOW(inter_fd,2));
+
+ if (battle_config.etc_log)
+ printf("intif_wis_message_to_gm: from: '%s', min level: %d, message: '%s'.\n", Wisp_name, min_gm_level, mes);
+
+ return 0;
+}
+
+// アカウント変数送信
+int intif_saveaccountreg(struct map_session_data *sd) {
+ int j,p;
+
+ nullpo_retr(0, sd);
+
+ WFIFOW(inter_fd,0) = 0x3004;
+ WFIFOL(inter_fd,4) = sd->bl.id;
+ for(j=0,p=8;j<sd->status.account_reg_num;j++,p+=36){
+ memcpy(WFIFOP(inter_fd,p),sd->status.account_reg[j].str,32);
+ WFIFOL(inter_fd,p+32)=sd->status.account_reg[j].value;
+ }
+ WFIFOW(inter_fd,2)=p;
+ WFIFOSET(inter_fd,p);
+ return 0;
+}
+// アカウント変数要求
+int intif_request_accountreg(struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+
+ WFIFOW(inter_fd,0) = 0x3005;
+ WFIFOL(inter_fd,2) = sd->bl.id;
+ WFIFOSET(inter_fd,6);
+ return 0;
+}
+
+// 倉庫データ要求
+int intif_request_storage(int account_id)
+{
+ WFIFOW(inter_fd,0) = 0x3010;
+ WFIFOL(inter_fd,2) = account_id;
+ WFIFOSET(inter_fd,6);
+ return 0;
+}
+// 倉庫データ送信
+int intif_send_storage(struct storage *stor)
+{
+ nullpo_retr(0, stor);
+ WFIFOW(inter_fd,0) = 0x3011;
+ WFIFOW(inter_fd,2) = sizeof(struct storage)+8;
+ WFIFOL(inter_fd,4) = stor->account_id;
+ memcpy( WFIFOP(inter_fd,8),stor, sizeof(struct storage) );
+ WFIFOSET(inter_fd,WFIFOW(inter_fd,2));
+ return 0;
+}
+
+int intif_request_guild_storage(int account_id,int guild_id)
+{
+ WFIFOW(inter_fd,0) = 0x3018;
+ WFIFOL(inter_fd,2) = account_id;
+ WFIFOL(inter_fd,6) = guild_id;
+ WFIFOSET(inter_fd,10);
+ return 0;
+}
+int intif_send_guild_storage(int account_id,struct guild_storage *gstor)
+{
+ WFIFOW(inter_fd,0) = 0x3019;
+ WFIFOW(inter_fd,2) = sizeof(struct guild_storage)+12;
+ WFIFOL(inter_fd,4) = account_id;
+ WFIFOL(inter_fd,8) = gstor->guild_id;
+ memcpy( WFIFOP(inter_fd,12),gstor, sizeof(struct guild_storage) );
+ WFIFOSET(inter_fd,WFIFOW(inter_fd,2));
+ return 0;
+}
+
+// パーティ作成要求
+int intif_create_party(struct map_session_data *sd,char *name)
+{
+ nullpo_retr(0, sd);
+
+ WFIFOW(inter_fd,0) = 0x3020;
+ WFIFOL(inter_fd,2) = sd->status.account_id;
+ memcpy(WFIFOP(inter_fd, 6),name,24);
+ memcpy(WFIFOP(inter_fd,30),sd->status.name,24);
+ memcpy(WFIFOP(inter_fd,54),map[sd->bl.m].name,16);
+ WFIFOW(inter_fd,70)= sd->status.base_level;
+ WFIFOSET(inter_fd,72);
+// if(battle_config.etc_log)
+// printf("intif: create party\n");
+ return 0;
+}
+// パーティ情報要求
+int intif_request_partyinfo(int party_id)
+{
+ WFIFOW(inter_fd,0) = 0x3021;
+ WFIFOL(inter_fd,2) = party_id;
+ WFIFOSET(inter_fd,6);
+// if(battle_config.etc_log)
+// printf("intif: request party info\n");
+ return 0;
+}
+// パーティ追加要求
+int intif_party_addmember(int party_id,int account_id)
+{
+ struct map_session_data *sd;
+ sd=map_id2sd(account_id);
+// if(battle_config.etc_log)
+// printf("intif: party add member %d %d\n",party_id,account_id);
+ if(sd!=NULL){
+ WFIFOW(inter_fd,0)=0x3022;
+ WFIFOL(inter_fd,2)=party_id;
+ WFIFOL(inter_fd,6)=account_id;
+ memcpy(WFIFOP(inter_fd,10),sd->status.name,24);
+ memcpy(WFIFOP(inter_fd,34),map[sd->bl.m].name,16);
+ WFIFOW(inter_fd,50)=sd->status.base_level;
+ WFIFOSET(inter_fd,52);
+ }
+ return 0;
+}
+// パーティ設定変更
+int intif_party_changeoption(int party_id,int account_id,int exp,int item)
+{
+ WFIFOW(inter_fd,0)=0x3023;
+ WFIFOL(inter_fd,2)=party_id;
+ WFIFOL(inter_fd,6)=account_id;
+ WFIFOW(inter_fd,10)=exp;
+ WFIFOW(inter_fd,12)=item;
+ WFIFOSET(inter_fd,14);
+ return 0;
+}
+// パーティ脱退要求
+int intif_party_leave(int party_id,int account_id)
+{
+// if(battle_config.etc_log)
+// printf("intif: party leave %d %d\n",party_id,account_id);
+ WFIFOW(inter_fd,0)=0x3024;
+ WFIFOL(inter_fd,2)=party_id;
+ WFIFOL(inter_fd,6)=account_id;
+ WFIFOSET(inter_fd,10);
+ return 0;
+}
+// パーティ移動要求
+int intif_party_changemap(struct map_session_data *sd,int online)
+{
+ if(sd!=NULL){
+ WFIFOW(inter_fd,0)=0x3025;
+ WFIFOL(inter_fd,2)=sd->status.party_id;
+ WFIFOL(inter_fd,6)=sd->status.account_id;
+ memcpy(WFIFOP(inter_fd,10),map[sd->bl.m].name,16);
+ WFIFOB(inter_fd,26)=online;
+ WFIFOW(inter_fd,27)=sd->status.base_level;
+ WFIFOSET(inter_fd,29);
+ }
+// if(battle_config.etc_log)
+// printf("party: change map\n");
+ return 0;
+}
+// パーティー解散要求
+int intif_break_party(int party_id)
+{
+ WFIFOW(inter_fd,0)=0x3026;
+ WFIFOL(inter_fd,2)=party_id;
+ WFIFOSET(inter_fd,6);
+ return 0;
+}
+// パーティ会話送信
+int intif_party_message(int party_id,int account_id,char *mes,int len)
+{
+// if(battle_config.etc_log)
+// printf("intif_party_message: %s\n",mes);
+ WFIFOW(inter_fd,0)=0x3027;
+ WFIFOW(inter_fd,2)=len+12;
+ WFIFOL(inter_fd,4)=party_id;
+ WFIFOL(inter_fd,8)=account_id;
+ memcpy(WFIFOP(inter_fd,12),mes,len);
+ WFIFOSET(inter_fd,len+12);
+ return 0;
+}
+// パーティ競合チェック要求
+int intif_party_checkconflict(int party_id,int account_id,char *nick)
+{
+ WFIFOW(inter_fd,0)=0x3028;
+ WFIFOL(inter_fd,2)=party_id;
+ WFIFOL(inter_fd,6)=account_id;
+ memcpy(WFIFOP(inter_fd,10),nick,24);
+ WFIFOSET(inter_fd,34);
+ return 0;
+}
+
+// ギルド作成要求
+int intif_guild_create(const char *name,const struct guild_member *master)
+{
+ nullpo_retr(0, master);
+
+ WFIFOW(inter_fd,0)=0x3030;
+ WFIFOW(inter_fd,2)=sizeof(struct guild_member)+32;
+ WFIFOL(inter_fd,4)=master->account_id;
+ memcpy(WFIFOP(inter_fd,8),name,24);
+ memcpy(WFIFOP(inter_fd,32),master,sizeof(struct guild_member));
+ WFIFOSET(inter_fd,WFIFOW(inter_fd,2));
+ return 0;
+}
+// ギルド情報要求
+int intif_guild_request_info(int guild_id)
+{
+ WFIFOW(inter_fd,0) = 0x3031;
+ WFIFOL(inter_fd,2) = guild_id;
+ WFIFOSET(inter_fd,6);
+ return 0;
+}
+// ギルドメンバ追加要求
+int intif_guild_addmember(int guild_id,struct guild_member *m)
+{
+ WFIFOW(inter_fd,0) = 0x3032;
+ WFIFOW(inter_fd,2) = sizeof(struct guild_member)+8;
+ WFIFOL(inter_fd,4) = guild_id;
+ memcpy(WFIFOP(inter_fd,8),m,sizeof(struct guild_member));
+ WFIFOSET(inter_fd,WFIFOW(inter_fd,2));
+ return 0;
+}
+// ギルドメンバ脱退/追放要求
+int intif_guild_leave(int guild_id,int account_id,int char_id,int flag,const char *mes)
+{
+ WFIFOW(inter_fd, 0) = 0x3034;
+ WFIFOL(inter_fd, 2) = guild_id;
+ WFIFOL(inter_fd, 6) = account_id;
+ WFIFOL(inter_fd,10) = char_id;
+ WFIFOB(inter_fd,14) = flag;
+ memcpy(WFIFOP(inter_fd,15),mes,40);
+ WFIFOSET(inter_fd,55);
+ return 0;
+}
+// ギルドメンバのオンライン状況/Lv更新要求
+int intif_guild_memberinfoshort(int guild_id,
+ int account_id,int char_id,int online,int lv,int class)
+{
+ WFIFOW(inter_fd, 0) = 0x3035;
+ WFIFOL(inter_fd, 2) = guild_id;
+ WFIFOL(inter_fd, 6) = account_id;
+ WFIFOL(inter_fd,10) = char_id;
+ WFIFOB(inter_fd,14) = online;
+ WFIFOW(inter_fd,15) = lv;
+ WFIFOW(inter_fd,17) = class;
+ WFIFOSET(inter_fd,19);
+ return 0;
+}
+// ギルド解散通知
+int intif_guild_break(int guild_id)
+{
+ WFIFOW(inter_fd, 0) = 0x3036;
+ WFIFOL(inter_fd, 2) = guild_id;
+ WFIFOSET(inter_fd,6);
+ return 0;
+}
+// ギルド会話送信
+int intif_guild_message(int guild_id,int account_id,char *mes,int len)
+{
+ WFIFOW(inter_fd,0)=0x3037;
+ WFIFOW(inter_fd,2)=len+12;
+ WFIFOL(inter_fd,4)=guild_id;
+ WFIFOL(inter_fd,8)=account_id;
+ memcpy(WFIFOP(inter_fd,12),mes,len);
+ WFIFOSET(inter_fd,len+12);
+ return 0;
+}
+// ギルド競合チェック要求
+int intif_guild_checkconflict(int guild_id,int account_id,int char_id)
+{
+ WFIFOW(inter_fd, 0)=0x3038;
+ WFIFOL(inter_fd, 2)=guild_id;
+ WFIFOL(inter_fd, 6)=account_id;
+ WFIFOL(inter_fd,10)=char_id;
+ WFIFOSET(inter_fd,14);
+ return 0;
+}
+// ギルド基本情報変更要求
+int intif_guild_change_basicinfo(int guild_id,int type,const void *data,int len)
+{
+ WFIFOW(inter_fd,0)=0x3039;
+ WFIFOW(inter_fd,2)=len+10;
+ WFIFOL(inter_fd,4)=guild_id;
+ WFIFOW(inter_fd,8)=type;
+ memcpy(WFIFOP(inter_fd,10),data,len);
+ WFIFOSET(inter_fd,len+10);
+ return 0;
+}
+// ギルドメンバ情報変更要求
+int intif_guild_change_memberinfo(int guild_id,int account_id,int char_id,
+ int type,const void *data,int len)
+{
+ WFIFOW(inter_fd, 0)=0x303a;
+ WFIFOW(inter_fd, 2)=len+18;
+ WFIFOL(inter_fd, 4)=guild_id;
+ WFIFOL(inter_fd, 8)=account_id;
+ WFIFOL(inter_fd,12)=char_id;
+ WFIFOW(inter_fd,16)=type;
+ memcpy(WFIFOP(inter_fd,18),data,len);
+ WFIFOSET(inter_fd,len+18);
+ return 0;
+}
+// ギルド役職変更要求
+int intif_guild_position(int guild_id,int idx,struct guild_position *p)
+{
+ WFIFOW(inter_fd,0)=0x303b;
+ WFIFOW(inter_fd,2)=sizeof(struct guild_position)+12;
+ WFIFOL(inter_fd,4)=guild_id;
+ WFIFOL(inter_fd,8)=idx;
+ memcpy(WFIFOP(inter_fd,12),p,sizeof(struct guild_position));
+ WFIFOSET(inter_fd,WFIFOW(inter_fd,2));
+ return 0;
+}
+// ギルドスキルアップ要求
+int intif_guild_skillup(int guild_id,int skill_num,int account_id,int flag)
+{
+ WFIFOW(inter_fd, 0)=0x303c;
+ WFIFOL(inter_fd, 2)=guild_id;
+ WFIFOL(inter_fd, 6)=skill_num;
+ WFIFOL(inter_fd,10)=account_id;
+ WFIFOL(inter_fd,14)=flag;
+ WFIFOSET(inter_fd,18);
+ return 0;
+}
+// ギルド同盟/敵対要求
+int intif_guild_alliance(int guild_id1,int guild_id2,int account_id1,int account_id2,int flag)
+{
+ WFIFOW(inter_fd, 0)=0x303d;
+ WFIFOL(inter_fd, 2)=guild_id1;
+ WFIFOL(inter_fd, 6)=guild_id2;
+ WFIFOL(inter_fd,10)=account_id1;
+ WFIFOL(inter_fd,14)=account_id2;
+ WFIFOB(inter_fd,18)=flag;
+ WFIFOSET(inter_fd,19);
+ return 0;
+}
+// ギルド告知変更要求
+int intif_guild_notice(int guild_id,const char *mes1,const char *mes2)
+{
+ WFIFOW(inter_fd,0)=0x303e;
+ WFIFOL(inter_fd,2)=guild_id;
+ memcpy(WFIFOP(inter_fd,6),mes1,60);
+ memcpy(WFIFOP(inter_fd,66),mes2,120);
+ WFIFOSET(inter_fd,186);
+ return 0;
+}
+// ギルドエンブレム変更要求
+int intif_guild_emblem(int guild_id,int len,const char *data)
+{
+ if(guild_id<=0 || len<0 || len>2000)
+ return 0;
+ WFIFOW(inter_fd,0)=0x303f;
+ WFIFOW(inter_fd,2)=len+12;
+ WFIFOL(inter_fd,4)=guild_id;
+ WFIFOL(inter_fd,8)=0;
+ memcpy(WFIFOP(inter_fd,12),data,len);
+ WFIFOSET(inter_fd,len+12);
+ return 0;
+}
+//現在のギルド城占領ギルドを調べる
+int intif_guild_castle_dataload(int castle_id,int index)
+{
+ WFIFOW(inter_fd,0)=0x3040;
+ WFIFOW(inter_fd,2)=castle_id;
+ WFIFOB(inter_fd,4)=index;
+ WFIFOSET(inter_fd,5);
+ return 0;
+}
+
+//ギルド城占領ギルド変更要求
+int intif_guild_castle_datasave(int castle_id,int index, int value)
+{
+ WFIFOW(inter_fd,0)=0x3041;
+ WFIFOW(inter_fd,2)=castle_id;
+ WFIFOB(inter_fd,4)=index;
+ WFIFOL(inter_fd,5)=value;
+ WFIFOSET(inter_fd,9);
+ return 0;
+}
+
+/*==========================================
+ * 指定した名前のキャラの場所要求
+ *------------------------------------------
+ */
+int intif_charposreq(int account_id,char *name,int flag)
+{
+ WFIFOW(inter_fd,0)=0x3090;
+ WFIFOL(inter_fd,2)=account_id;
+ memcpy(WFIFOP(inter_fd,6),name,24);
+ WFIFOB(inter_fd,30)=flag;
+ WFIFOSET(inter_fd,31);
+ return 0;
+}
+
+/*==========================================
+ * 指定した名前のキャラの場所に移動する
+ * @jumpto
+ *------------------------------------------
+ */
+int intif_jumpto(int account_id,char *name)
+{
+ intif_charposreq(account_id,name,1);
+ //printf("intif_jumpto: %d %s\n",account_id,name);
+ return 0;
+}
+
+/*==========================================
+ * 指定した名前のキャラの場所表示する
+ * @where
+ *------------------------------------------
+ */
+int intif_where(int account_id,char *name)
+{
+ intif_charposreq(account_id,name,0);
+ //printf("intif_where: %d %s\n",account_id,name);
+ return 0;
+}
+
+/*==========================================
+ * 指定した名前のキャラを呼び寄せる
+ * flag=0 あなたに逢いたい
+ * flag=1 @recall
+ *------------------------------------------
+ */
+int intif_charmovereq(struct map_session_data *sd,char *name,int flag)
+{
+ nullpo_retr(0,sd);
+
+ //printf("intif_charmovereq: %d %s\n",sd->status.account_id,name);
+ if(name==NULL)
+ return -1;
+
+ WFIFOW(inter_fd,0)=0x3092;
+ WFIFOL(inter_fd,2)=sd->status.account_id;
+ memcpy(WFIFOP(inter_fd,6),name,24);
+ WFIFOB(inter_fd,30)=flag;
+ memcpy(WFIFOP(inter_fd,31),sd->mapname,16);
+ WFIFOW(inter_fd,47)=sd->bl.x;
+ WFIFOW(inter_fd,49)=sd->bl.y;
+ WFIFOSET(inter_fd,51);
+ return 0;
+}
+/*==========================================
+ * 対象IDにメッセージを送信
+ *------------------------------------------
+ */
+int intif_displaymessage(int account_id, char* mes)
+{
+ int len = 6+strlen(mes)+1;
+ WFIFOW(inter_fd,0) = 0x3093;
+ WFIFOW(inter_fd,2) = len;
+ WFIFOL(inter_fd,4) = account_id;
+ strncpy(WFIFOP(inter_fd,8), mes, len-6);
+ WFIFOSET(inter_fd, len );
+
+ return 0;
+}
+//-----------------------------------------------------------------
+// Packets receive from inter server
+
+// Wisp/Page reception
+int intif_parse_WisMessage(int fd) { // rewritten by [Yor]
+ struct map_session_data* sd;
+ int id=RFIFOL(fd,4);
+ int i,j=0;
+
+// if(battle_config.etc_log)
+// printf("intif_parse_wismessage: %d %s %s %s\n",id,RFIFOP(fd,6),RFIFOP(fd,30),RFIFOP(fd,54) );
+
+ sd=map_nick2sd(RFIFOP(fd,32)); // 送信先を探す
+ if(sd!=NULL){
+ for(i=0;i<MAX_WIS_REFUSAL;i++){ //拒否リストに名前があるかどうか判定してあれば拒否
+ if(strcmp(sd->wis_refusal[i],RFIFOP(fd,8))==0){
+ j++;
+ break;
+ }
+ }
+ if(sd->wis_all)
+ intif_wis_replay(id,3); // 受信拒否
+ else if(j>0)
+ intif_wis_replay(id,2); // 受信拒否
+ else{
+ clif_wis_message(sd->fd,RFIFOP(fd,8),RFIFOP(fd,56),RFIFOW(fd,2)-56);
+ intif_wis_replay(id,0); // 送信成功
+ }
+ }else
+ intif_wis_replay(id,1); // そんな人いません
+ return 0;
+}
+
+// Wisp/page transmission result reception
+int intif_parse_WisEnd(int fd) {
+ struct map_session_data* sd;
+
+ if (battle_config.etc_log)
+ printf("intif_parse_wisend: player: %s, flag: %d\n", RFIFOP(fd,2), RFIFOB(fd,26)); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
+ sd = map_nick2sd(RFIFOP(fd,2));
+ if (sd != NULL)
+ clif_wis_end(sd->fd, RFIFOB(fd,26));
+
+ return 0;
+}
+
+// Received wisp message from map-server via char-server for ALL gm
+int mapif_parse_WisToGM(int fd) { // 0x3003/0x3803 <packet_len>.w <wispname>.24B <min_gm_level>.w <message>.?B
+ int i, min_gm_level;
+ struct map_session_data *pl_sd;
+ char Wisp_name[24];
+ char mbuf[255];
+ char *message = ((RFIFOW(fd,2) - 30) >= sizeof(mbuf)) ? (char *) malloc((RFIFOW(fd,2) - 30)) : mbuf;
+
+ min_gm_level = (int)RFIFOW(fd,28);
+ memcpy(Wisp_name, RFIFOP(fd,4), 24);
+ Wisp_name[23] = '\0';
+ memcpy(message, RFIFOP(fd,30), RFIFOW(fd,2) - 30);
+ message[sizeof(message) - 1] = '\0';
+ // information is sended to all online GM
+ for (i = 0; i < fd_max; i++)
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth)
+ if (pc_isGM(pl_sd) >= min_gm_level)
+ clif_wis_message(i, Wisp_name, message, strlen(message) + 1);
+
+ if (message != mbuf)
+ free(message);
+
+ return 0;
+}
+
+// アカウント変数通知
+int intif_parse_AccountReg(int fd) {
+ int j,p;
+ struct map_session_data *sd;
+
+ if( (sd=map_id2sd(RFIFOL(fd,4)))==NULL )
+ return 1;
+ for(p=8,j=0;p<RFIFOW(fd,2) && j<ACCOUNT_REG_NUM;p+=36,j++){
+ memcpy(sd->status.account_reg[j].str,RFIFOP(fd,p),32);
+ sd->status.account_reg[j].value=RFIFOL(fd,p+32);
+ }
+ sd->status.account_reg_num = j;
+// printf("intif: accountreg\n");
+
+ return 0;
+}
+
+// 倉庫データ受信
+int intif_parse_LoadStorage(int fd) {
+ struct storage *stor;
+ struct map_session_data *sd;
+
+ stor = account2storage( RFIFOL(fd,4));
+ if (RFIFOW(fd,2)-8 != sizeof(struct storage)) {
+ if (battle_config.error_log)
+ printf("intif_parse_LoadStorage: data size error %d %d\n", RFIFOW(fd,2)-8, sizeof(struct storage));
+ return 1;
+ }
+ sd=map_id2sd( RFIFOL(fd,4) );
+ if(sd==NULL){
+ if(battle_config.error_log)
+ printf("intif_parse_LoadStorage: user not found %d\n",RFIFOL(fd,4));
+ return 1;
+ }
+ if(battle_config.save_log)
+ printf("intif_openstorage: %d\n",RFIFOL(fd,4) );
+ memcpy(stor,RFIFOP(fd,8),sizeof(struct storage));
+ stor->storage_status=1;
+ sd->state.storage_flag = 0;
+ clif_storageitemlist(sd,stor);
+ clif_storageequiplist(sd,stor);
+ clif_updatestorageamount(sd,stor);
+
+ return 0;
+}
+
+// 倉庫データ送信成功
+int intif_parse_SaveStorage(int fd)
+{
+ if(battle_config.save_log)
+ printf("intif_savestorage: done %d %d\n",RFIFOL(fd,2),RFIFOB(fd,6) );
+ return 0;
+}
+
+int intif_parse_LoadGuildStorage(int fd)
+{
+ struct guild_storage *gstor;
+ struct map_session_data *sd;
+ int guild_id = RFIFOL(fd,8);
+ if(guild_id > 0) {
+ gstor=guild2storage(guild_id);
+ if(!gstor) {
+ if(battle_config.error_log)
+ printf("intif_parse_LoadGuildStorage: error guild_id %d not exist\n",guild_id);
+ return 1;
+ }
+ if( RFIFOW(fd,2)-12 != sizeof(struct guild_storage) ){
+ gstor->storage_status = 0;
+ if(battle_config.error_log)
+ printf("intif_parse_LoadGuildStorage: data size error %d %d\n",RFIFOW(fd,2)-12 , sizeof(struct guild_storage));
+ return 1;
+ }
+ sd=map_id2sd( RFIFOL(fd,4) );
+ if(sd==NULL){
+ if(battle_config.error_log)
+ printf("intif_parse_LoadGuildStorage: user not found %d\n",RFIFOL(fd,4));
+ return 1;
+ }
+ if(battle_config.save_log)
+ printf("intif_open_guild_storage: %d\n",RFIFOL(fd,4) );
+ memcpy(gstor,RFIFOP(fd,12),sizeof(struct guild_storage));
+ gstor->storage_status = 1;
+ sd->state.storage_flag = 1;
+ clif_guildstorageitemlist(sd,gstor);
+ clif_guildstorageequiplist(sd,gstor);
+ clif_updateguildstorageamount(sd,gstor);
+ }
+ return 0;
+}
+int intif_parse_SaveGuildStorage(int fd)
+{
+ if(battle_config.save_log) {
+ printf("intif_save_guild_storage: done %d %d %d\n",RFIFOL(fd,2),RFIFOL(fd,6),RFIFOB(fd,10) );
+ }
+ return 0;
+}
+
+// パーティ作成可否
+int intif_parse_PartyCreated(int fd)
+{
+ if(battle_config.etc_log)
+ printf("intif: party created\n");
+ party_created(RFIFOL(fd,2),RFIFOB(fd,6),RFIFOL(fd,7),RFIFOP(fd,11));
+ return 0;
+}
+// パーティ情報
+int intif_parse_PartyInfo(int fd)
+{
+ if( RFIFOW(fd,2)==8){
+ if(battle_config.error_log)
+ printf("intif: party noinfo %d\n",RFIFOL(fd,4));
+ party_recv_noinfo(RFIFOL(fd,4));
+ return 0;
+ }
+
+// printf("intif: party info %d\n",RFIFOL(fd,4));
+ if( RFIFOW(fd,2)!=sizeof(struct party)+4 ){
+ if(battle_config.error_log)
+ printf("intif: party info : data size error %d %d %d\n",RFIFOL(fd,4),RFIFOW(fd,2),sizeof(struct party)+4);
+ }
+ party_recv_info((struct party *)RFIFOP(fd,4));
+ return 0;
+}
+// パーティ追加通知
+int intif_parse_PartyMemberAdded(int fd)
+{
+ if(battle_config.etc_log)
+ printf("intif: party member added %d %d %d\n",RFIFOL(fd,2),RFIFOL(fd,6),RFIFOB(fd,10));
+ party_member_added(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOB(fd,10));
+ return 0;
+}
+// パーティ設定変更通知
+int intif_parse_PartyOptionChanged(int fd)
+{
+ party_optionchanged(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOW(fd,10),RFIFOW(fd,12),RFIFOB(fd,14));
+ return 0;
+}
+// パーティ脱退通知
+int intif_parse_PartyMemberLeaved(int fd)
+{
+ if(battle_config.etc_log)
+ printf("intif: party member leaved %d %d %s\n",RFIFOL(fd,2),RFIFOL(fd,6),RFIFOP(fd,10));
+ party_member_leaved(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOP(fd,10));
+ return 0;
+}
+// パーティ解散通知
+int intif_parse_PartyBroken(int fd)
+{
+ party_broken(RFIFOL(fd,2));
+ return 0;
+}
+// パーティ移動通知
+int intif_parse_PartyMove(int fd)
+{
+// if(battle_config.etc_log)
+// printf("intif: party move %d %d %s %d %d\n",RFIFOL(fd,2),RFIFOL(fd,6),RFIFOP(fd,10),RFIFOB(fd,26),RFIFOW(fd,27));
+ party_recv_movemap(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOP(fd,10),RFIFOB(fd,26),RFIFOW(fd,27));
+ return 0;
+}
+// パーティメッセージ
+int intif_parse_PartyMessage(int fd)
+{
+// if(battle_config.etc_log)
+// printf("intif_parse_PartyMessage: %s\n",RFIFOP(fd,12));
+ party_recv_message(RFIFOL(fd,4),RFIFOL(fd,8),RFIFOP(fd,12),RFIFOW(fd,2)-12);
+ return 0;
+}
+
+// ギルド作成可否
+int intif_parse_GuildCreated(int fd)
+{
+ guild_created(RFIFOL(fd,2),RFIFOL(fd,6));
+ return 0;
+}
+// ギルド情報
+int intif_parse_GuildInfo(int fd)
+{
+ if( RFIFOW(fd,2)==8){
+ if(battle_config.error_log)
+ printf("intif: guild noinfo %d\n",RFIFOL(fd,4));
+ guild_recv_noinfo(RFIFOL(fd,4));
+ return 0;
+ }
+
+// if(battle_config.etc_log)
+// printf("intif: guild info %d\n",RFIFOL(fd,4));
+ if( RFIFOW(fd,2)!=sizeof(struct guild)+4 ){
+ if(battle_config.error_log)
+ printf("intif: guild info : data size error\n %d %d %d",RFIFOL(fd,4),RFIFOW(fd,2),sizeof(struct guild)+4);
+ }
+ guild_recv_info((struct guild *)RFIFOP(fd,4));
+ return 0;
+}
+// ギルドメンバ追加通知
+int intif_parse_GuildMemberAdded(int fd)
+{
+ if(battle_config.etc_log)
+ printf("intif: guild member added %d %d %d %d\n",RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14));
+ guild_member_added(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14));
+ return 0;
+}
+// ギルドメンバ脱退/追放通知
+int intif_parse_GuildMemberLeaved(int fd)
+{
+ guild_member_leaved(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),
+ RFIFOP(fd,55),RFIFOP(fd,15));
+ return 0;
+}
+
+// ギルドメンバオンライン状態/Lv変更通知
+int intif_parse_GuildMemberInfoShort(int fd)
+{
+ guild_recv_memberinfoshort(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),RFIFOW(fd,15),RFIFOW(fd,17));
+ return 0;
+}
+// ギルド解散通知
+int intif_parse_GuildBroken(int fd)
+{
+ guild_broken(RFIFOL(fd,2),RFIFOB(fd,6));
+ return 0;
+}
+
+// ギルド基本情報変更通知
+int intif_parse_GuildBasicInfoChanged(int fd)
+{
+ int type=RFIFOW(fd,8),guild_id=RFIFOL(fd,4);
+ void *data=RFIFOP(fd,10);
+ struct guild *g=guild_search(guild_id);
+ short dw=*((short *)data);
+ int dd=*((int *)data);
+ if( g==NULL )
+ return 0;
+ switch(type){
+ case GBI_EXP: g->exp=dd; break;
+ case GBI_GUILDLV: g->guild_lv=dw; break;
+ case GBI_SKILLPOINT: g->skill_point=dd; break;
+ }
+ return 0;
+}
+// ギルドメンバ情報変更通知
+int intif_parse_GuildMemberInfoChanged(int fd)
+{
+ int type=RFIFOW(fd,16),guild_id=RFIFOL(fd,4);
+ int account_id=RFIFOL(fd,8),char_id=RFIFOL(fd,12);
+ void *data=RFIFOP(fd,18);
+ struct guild *g=guild_search(guild_id);
+ int idx,dd=*((int *)data);
+ if( g==NULL )
+ return 0;
+ idx=guild_getindex(g,account_id,char_id);
+ switch(type){
+ case GMI_POSITION:
+ g->member[idx].position=dd;
+ guild_memberposition_changed(g,idx,dd);
+ break;
+ case GMI_EXP:
+ g->member[idx].exp=dd;
+ break;
+ }
+ return 0;
+}
+
+// ギルド役職変更通知
+int intif_parse_GuildPosition(int fd)
+{
+ if( RFIFOW(fd,2)!=sizeof(struct guild_position)+12 ){
+ if(battle_config.error_log)
+ printf("intif: guild info : data size error\n %d %d %d",RFIFOL(fd,4),RFIFOW(fd,2),sizeof(struct guild_position)+12);
+ }
+ guild_position_changed(RFIFOL(fd,4),RFIFOL(fd,8),(struct guild_position *)RFIFOP(fd,12));
+ return 0;
+}
+// ギルドスキル割り振り通知
+int intif_parse_GuildSkillUp(int fd)
+{
+ guild_skillupack(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10));
+ return 0;
+}
+// ギルド同盟/敵対通知
+int intif_parse_GuildAlliance(int fd)
+{
+ guild_allianceack(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14),
+ RFIFOB(fd,18),RFIFOP(fd,19),RFIFOP(fd,43));
+ return 0;
+}
+// ギルド告知変更通知
+int intif_parse_GuildNotice(int fd)
+{
+ guild_notice_changed(RFIFOL(fd,2),RFIFOP(fd,6),RFIFOP(fd,66));
+ return 0;
+}
+// ギルドエンブレム変更通知
+int intif_parse_GuildEmblem(int fd)
+{
+ guild_emblem_changed(RFIFOW(fd,2)-12,RFIFOL(fd,4),RFIFOL(fd,8),RFIFOP(fd,12));
+ return 0;
+}
+// ギルド会話受信
+int intif_parse_GuildMessage(int fd)
+{
+ guild_recv_message(RFIFOL(fd,4),RFIFOL(fd,8),RFIFOP(fd,12),RFIFOW(fd,2)-12);
+ return 0;
+}
+// ギルド城データ要求返信
+int intif_parse_GuildCastleDataLoad(int fd)
+{
+ return guild_castledataloadack(RFIFOW(fd,2),RFIFOB(fd,4),RFIFOL(fd,5));
+}
+// ギルド城データ変更通知
+int intif_parse_GuildCastleDataSave(int fd)
+{
+ return guild_castledatasaveack(RFIFOW(fd,2),RFIFOB(fd,4),RFIFOL(fd,5));
+}
+
+// ギルド城データ一括受信(初期化時)
+int intif_parse_GuildCastleAllDataLoad(int fd)
+{
+ return guild_castlealldataload(RFIFOW(fd,2),(struct guild_castle *)RFIFOP(fd,4));
+}
+
+// pet
+int intif_parse_CreatePet(int fd)
+{
+ pet_get_egg(RFIFOL(fd,2),RFIFOL(fd,7),RFIFOB(fd,6));
+
+ return 0;
+}
+
+int intif_parse_RecvPetData(int fd)
+{
+ struct s_pet p;
+ int len=RFIFOW(fd,2);
+ if(sizeof(struct s_pet)!=len-9) {
+ if(battle_config.etc_log)
+ printf("intif: pet data: data size error %d %d\n",sizeof(struct s_pet),len-9);
+ }
+ else{
+ memcpy(&p,RFIFOP(fd,9),sizeof(struct s_pet));
+ pet_recv_petdata(RFIFOL(fd,4),&p,RFIFOB(fd,8));
+ }
+
+ return 0;
+}
+int intif_parse_SavePetOk(int fd)
+{
+ if(RFIFOB(fd,6) == 1) {
+ if(battle_config.error_log)
+ printf("pet data save failure\n");
+ }
+
+ return 0;
+}
+
+int intif_parse_DeletePetOk(int fd)
+{
+ if(RFIFOB(fd,2) == 1) {
+ if(battle_config.error_log)
+ printf("pet data delete failure\n");
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------
+// inter serverからの通信
+// エラーがあれば0(false)を返すこと
+// パケットが処理できれば1,パケット長が足りなければ2を返すこと
+int intif_parse(int fd)
+{
+ int packet_len;
+ int cmd = RFIFOW(fd,0);
+ // パケットのID確認
+ if(cmd<0x3800 || cmd>=0x3800+(sizeof(packet_len_table)/sizeof(packet_len_table[0])) ||
+ packet_len_table[cmd-0x3800]==0){
+ return 0;
+ }
+ // パケットの長さ確認
+ packet_len = packet_len_table[cmd-0x3800];
+ if(packet_len==-1){
+ if(RFIFOREST(fd)<4)
+ return 2;
+ packet_len = RFIFOW(fd,2);
+ }
+// if(battle_config.etc_log)
+// printf("intif_parse %d %x %d %d\n",fd,cmd,packet_len,RFIFOREST(fd));
+ if(RFIFOREST(fd)<packet_len){
+ return 2;
+ }
+ // 処理分岐
+ switch(cmd){
+ case 0x3800: clif_GMmessage(NULL,RFIFOP(fd,4),packet_len-4,0); break;
+ case 0x3801: intif_parse_WisMessage(fd); break;
+ case 0x3802: intif_parse_WisEnd(fd); break;
+ case 0x3803: mapif_parse_WisToGM(fd); break;
+ case 0x3804: intif_parse_AccountReg(fd); break;
+ case 0x3810: intif_parse_LoadStorage(fd); break;
+ case 0x3811: intif_parse_SaveStorage(fd); break;
+ case 0x3818: intif_parse_LoadGuildStorage(fd); break;
+ case 0x3819: intif_parse_SaveGuildStorage(fd); break;
+ case 0x3820: intif_parse_PartyCreated(fd); break;
+ case 0x3821: intif_parse_PartyInfo(fd); break;
+ case 0x3822: intif_parse_PartyMemberAdded(fd); break;
+ case 0x3823: intif_parse_PartyOptionChanged(fd); break;
+ case 0x3824: intif_parse_PartyMemberLeaved(fd); break;
+ case 0x3825: intif_parse_PartyMove(fd); break;
+ case 0x3826: intif_parse_PartyBroken(fd); break;
+ case 0x3827: intif_parse_PartyMessage(fd); break;
+ case 0x3830: intif_parse_GuildCreated(fd); break;
+ case 0x3831: intif_parse_GuildInfo(fd); break;
+ case 0x3832: intif_parse_GuildMemberAdded(fd); break;
+ case 0x3834: intif_parse_GuildMemberLeaved(fd); break;
+ case 0x3835: intif_parse_GuildMemberInfoShort(fd); break;
+ case 0x3836: intif_parse_GuildBroken(fd); break;
+ case 0x3837: intif_parse_GuildMessage(fd); break;
+ case 0x3839: intif_parse_GuildBasicInfoChanged(fd); break;
+ case 0x383a: intif_parse_GuildMemberInfoChanged(fd); break;
+ case 0x383b: intif_parse_GuildPosition(fd); break;
+ case 0x383c: intif_parse_GuildSkillUp(fd); break;
+ case 0x383d: intif_parse_GuildAlliance(fd); break;
+ case 0x383e: intif_parse_GuildNotice(fd); break;
+ case 0x383f: intif_parse_GuildEmblem(fd); break;
+ case 0x3840: intif_parse_GuildCastleDataLoad(fd); break;
+ case 0x3841: intif_parse_GuildCastleDataSave(fd); break;
+ case 0x3842: intif_parse_GuildCastleAllDataLoad(fd); break;
+ case 0x3880: intif_parse_CreatePet(fd); break;
+ case 0x3881: intif_parse_RecvPetData(fd); break;
+ case 0x3882: intif_parse_SavePetOk(fd); break;
+ case 0x3883: intif_parse_DeletePetOk(fd); break;
+ default:
+ if(battle_config.error_log)
+ printf("intif_parse : unknown packet %d %x\n",fd,RFIFOW(fd,0));
+ return 0;
+ }
+ // パケット読み飛ばし
+ RFIFOSKIP(fd,packet_len);
+ return 1;
+}
diff --git a/src/map/intif.h b/src/map/intif.h
new file mode 100644
index 000000000..bb5fcd379
--- /dev/null
+++ b/src/map/intif.h
@@ -0,0 +1,60 @@
+// $Id: intif.h,v 1.2 2004/09/25 05:32:18 MouseJstr Exp $
+#ifndef _INTIF_H_
+#define _INFIF_H_
+
+int intif_parse(int fd);
+
+int intif_GMmessage(char* mes,int len,int flag);
+
+int intif_wis_message(struct map_session_data *sd,char *nick,char *mes,int mes_len);
+int intif_wis_message_to_gm(char *Wisp_name, int min_gm_level, char *mes, int mes_len);
+
+int intif_saveaccountreg(struct map_session_data *sd);
+int intif_request_accountreg(struct map_session_data *sd);
+
+int intif_request_storage(int account_id);
+int intif_send_storage(struct storage *stor);
+int intif_request_guild_storage(int account_id, int guild_id);
+int intif_send_guild_storage(int account_id, struct guild_storage *gstor);
+
+
+int intif_create_party(struct map_session_data *sd,char *name);
+int intif_request_partyinfo(int party_id);
+int intif_party_addmember(int party_id, int account_id);
+int intif_party_changeoption(int party_id, int account_id, int exp, int item);
+int intif_party_leave(int party_id, int accound_id);
+int intif_party_changemap(struct map_session_data *sd, int online);
+int intif_break_party(int party_id);
+int intif_party_message(int party_id, int account_id, char *mes,int len);
+int intif_party_checkconflict(int party_id, int account_id, char *nick);
+
+
+int intif_guild_create(const char *name, const struct guild_member *master);
+int intif_guild_request_info(int guild_id);
+int intif_guild_addmember(int guild_id, struct guild_member *m);
+int intif_guild_leave(int guild_id, int account_id, int char_id, int flag, const char *mes);
+int intif_guild_memberinfoshort(int guild_id, int account_id, int char_id, int online, int lv, int class);
+int intif_guild_break(int guild_id);
+int intif_guild_message(int guild_id, int account_id, char *mes, int len);
+int intif_guild_checkconflict(int guild_id, int account_id, int char_id);
+int intif_guild_change_basicinfo(int guild_id, int type, const void *data, int len);
+int intif_guild_change_memberinfo(int guild_id, int account_id, int char_id, int type, const void *data, int len);
+int intif_guild_position(int guild_id, int idx, struct guild_position *p);
+int intif_guild_skillup(int guild_id, int skill_num, int account_id, int flag);
+int intif_guild_alliance(int guild_id1, int guild_id2, int account_id1, int account_id2, int flag);
+int intif_guild_notice(int guild_id, const char *mes1, const char *mes2);
+int intif_guild_emblem(int guild_id, int len, const char *data);
+int intif_guild_castle_dataload(int castle_id, int index);
+int intif_guild_castle_datasave(int castle_id, int index, int value);
+
+int intif_create_pet(int account_id, int char_id, short pet_type, short pet_lv, short pet_egg_id,
+ short pet_equip, short intimate, short hungry, char rename_flag, char incuvate, char *pet_name);
+int intif_request_petdata(int account_id, int char_id, int pet_id);
+int intif_save_petdata(int account_id, struct s_pet *p);
+int intif_delete_petdata(int pet_id);
+
+int intif_jumpto(int account_id,char *name);
+int intif_where(int account_id,char *name);
+int intif_charmovereq(struct map_session_data *sd,char *name,int flag);
+
+#endif
diff --git a/src/map/itemdb.c b/src/map/itemdb.c
new file mode 100644
index 000000000..095e053c2
--- /dev/null
+++ b/src/map/itemdb.c
@@ -0,0 +1,882 @@
+// $Id: itemdb.c,v 1.3 2004/09/25 05:32:18 MouseJstr Exp $
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db.h"
+#include "grfio.h"
+#include "nullpo.h"
+#include "malloc.h"
+#include "map.h"
+#include "battle.h"
+#include "itemdb.h"
+#include "script.h"
+#include "pc.h"
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+#define MAX_RANDITEM 2000
+
+// ** ITEMDB_OVERRIDE_NAME_VERBOSE **
+// 定義すると、itemdb.txtとgrfで名前が異なる場合、表示します.
+//#define ITEMDB_OVERRIDE_NAME_VERBOSE 1
+
+static struct dbt* item_db;
+
+static struct random_item_data blue_box[MAX_RANDITEM],violet_box[MAX_RANDITEM],card_album[MAX_RANDITEM],gift_box[MAX_RANDITEM],scroll[MAX_RANDITEM];
+static int blue_box_count=0,violet_box_count=0,card_album_count=0,gift_box_count=0,scroll_count=0;
+static int blue_box_default=0,violet_box_default=0,card_album_default=0,gift_box_default=0,scroll_default=0;
+
+// Function declarations
+
+static void itemdb_read(void);
+static int itemdb_readdb(void);
+#ifndef TXT_ONLY
+static int itemdb_read_sqldb(void);
+#endif /* not TXT_ONLY */
+static int itemdb_read_randomitem();
+static int itemdb_read_itemavail(void);
+static int itemdb_read_itemnametable(void);
+static int itemdb_read_noequip(void);
+void itemdb_reload(void);
+
+/*==========================================
+ * 名前で検索用
+ *------------------------------------------
+ */
+// name = item alias, so we should find items aliases first. if not found then look for "jname" (full name)
+int itemdb_searchname_sub(void *key,void *data,va_list ap)
+{
+ struct item_data *item=(struct item_data *)data,**dst;
+ char *str;
+ str=va_arg(ap,char *);
+ dst=va_arg(ap,struct item_data **);
+// if( strcmpi(item->name,str)==0 || strcmp(item->jname,str)==0 ||
+// memcmp(item->name,str,24)==0 || memcmp(item->jname,str,24)==0 )
+ if( strcmpi(item->name,str)==0 ) //by lupus
+ *dst=item;
+ return 0;
+}
+
+/*==========================================
+ * 名前で検索用
+ *------------------------------------------
+ */
+int itemdb_searchjname_sub(void *key,void *data,va_list ap)
+{
+ struct item_data *item=(struct item_data *)data,**dst;
+ char *str;
+ str=va_arg(ap,char *);
+ dst=va_arg(ap,struct item_data **);
+ if( strcmpi(item->jname,str)==0 )
+ *dst=item;
+ return 0;
+}
+/*==========================================
+ * 名前で検索
+ *------------------------------------------
+ */
+struct item_data* itemdb_searchname(const char *str)
+{
+ struct item_data *item=NULL;
+ numdb_foreach(item_db,itemdb_searchname_sub,str,&item);
+ return item;
+}
+
+/*==========================================
+ * 箱系アイテム検索
+ *------------------------------------------
+ */
+int itemdb_searchrandomid(int flags)
+{
+ int nameid=0,i,index,count;
+ struct random_item_data *list=NULL;
+
+ struct {
+ int nameid,count;
+ struct random_item_data *list;
+ } data[] ={
+ { 0,0,NULL },
+ { blue_box_default ,blue_box_count ,blue_box },
+ { violet_box_default,violet_box_count ,violet_box },
+ { card_album_default,card_album_count ,card_album },
+ { gift_box_default ,gift_box_count ,gift_box },
+ { scroll_default ,scroll_count ,scroll },
+ };
+
+ if(flags>=1 && flags<=5){
+ nameid=data[flags].nameid;
+ count=data[flags].count;
+ list=data[flags].list;
+
+ if(count > 0) {
+ for(i=0;i<1000;i++) {
+ index = rand()%count;
+ if( rand()%1000000 < list[index].per) {
+ nameid = list[index].nameid;
+ break;
+ }
+ }
+ }
+ }
+ return nameid;
+}
+
+/*==========================================
+ * DBの存在確認
+ *------------------------------------------
+ */
+struct item_data* itemdb_exists(int nameid)
+{
+ return numdb_search(item_db,nameid);
+}
+/*==========================================
+ * DBの検索
+ *------------------------------------------
+ */
+struct item_data* itemdb_search(int nameid)
+{
+ struct item_data *id;
+
+ id=numdb_search(item_db,nameid);
+ if(id) return id;
+
+ id=(struct item_data *)aCalloc(1,sizeof(struct item_data));
+ numdb_insert(item_db,nameid,id);
+
+ id->nameid=nameid;
+ id->value_buy=10;
+ id->value_sell=id->value_buy/2;
+ id->weight=10;
+ id->sex=2;
+ id->elv=0;
+ id->class=0xffffffff;
+ id->flag.available=0;
+ id->flag.value_notdc=0; //一応・・・
+ id->flag.value_notoc=0;
+ id->flag.no_equip=0;
+ id->view_id=0;
+
+ if(nameid>500 && nameid<600)
+ id->type=0; //heal item
+ else if(nameid>600 && nameid<700)
+ id->type=2; //use item
+ else if((nameid>700 && nameid<1100) ||
+ (nameid>7000 && nameid<8000))
+ id->type=3; //correction
+ else if(nameid>=1750 && nameid<1771)
+ id->type=10; //arrow
+ else if(nameid>1100 && nameid<2000)
+ id->type=4; //weapon
+ else if((nameid>2100 && nameid<3000) ||
+ (nameid>5000 && nameid<6000))
+ id->type=5; //armor
+ else if(nameid>4000 && nameid<5000)
+ id->type=6; //card
+ else if(nameid>9000 && nameid<10000)
+ id->type=7; //egg
+ else if(nameid>10000)
+ id->type=8; //petequip
+
+ return id;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int itemdb_isequip(int nameid)
+{
+ int type=itemdb_type(nameid);
+ if(type==0 || type==2 || type==3 || type==6 || type==10)
+ return 0;
+ return 1;
+}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int itemdb_isequip2(struct item_data *data)
+{
+ if(data) {
+ int type=data->type;
+ if(type==0 || type==2 || type==3 || type==6 || type==10)
+ return 0;
+ else
+ return 1;
+ }
+ return 0;
+}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int itemdb_isequip3(int nameid)
+{
+ int type=itemdb_type(nameid);
+ if(type==4 || type==5 || type == 8)
+ return 1;
+ return 0;
+}
+
+/*==========================================
+ * 捨てられるアイテムは1、そうでないアイテムは0
+ *------------------------------------------
+ */
+int itemdb_isdropable(int nameid)
+{
+ //結婚指輪は捨てられない
+ switch(nameid){
+ case 2634: //結婚指輪
+ case 2635: //結婚指輪
+ return 0;
+ }
+
+ return 1;
+}
+
+//
+// 初期化
+//
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static int itemdb_read_itemslottable(void)
+{
+ char *buf,*p;
+ int s;
+
+ buf=grfio_read("data\\itemslottable.txt");
+ if(buf==NULL)
+ return -1;
+ s=grfio_size("data\\itemslottable.txt");
+ buf[s]=0;
+ for(p=buf;p-buf<s;){
+ int nameid,equip;
+ sscanf(p,"%d#%d#",&nameid,&equip);
+ itemdb_search(nameid)->equip=equip;
+ p=strchr(p,10);
+ if(!p) break;
+ p++;
+ p=strchr(p,10);
+ if(!p) break;
+ p++;
+ }
+ free(buf);
+
+ return 0;
+}
+
+#ifndef TXT_ONLY
+/*====================================
+ * Removed item_value_db, don't re-add
+ *------------------------------------
+ */
+static void itemdb_read(void)
+{
+ itemdb_read_itemslottable();
+
+ if (db_use_sqldbs)
+ {
+ itemdb_read_sqldb();
+ }
+ else
+ {
+ itemdb_readdb();
+ }
+
+ itemdb_read_randomitem();
+ itemdb_read_itemavail();
+ itemdb_read_noequip();
+
+ if (!battle_config.item_name_override_grffile)
+ itemdb_read_itemnametable();
+}
+
+#endif /* not TXT_ONLY */
+/*==========================================
+ * アイテムデータベースの読み込み
+ *------------------------------------------
+ */
+static int itemdb_readdb(void)
+{
+ FILE *fp;
+ char line[1024];
+ int ln=0,lines=0;
+ int nameid,j;
+ char *str[32],*p,*np;
+ struct item_data *id;
+ int i=0;
+ char *filename[]={ "db/item_db.txt","db/item_db2.txt" };
+
+ for(i=0;i<2;i++){
+
+ fp=fopen(filename[i],"r");
+ if(fp==NULL){
+ if(i>0)
+ continue;
+ printf("can't read %s\n",filename[i]);
+ exit(1);
+ }
+
+ lines=0;
+ while(fgets(line,1020,fp)){
+ lines++;
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ memset(str,0,sizeof(str));
+ for(j=0,np=p=line;j<17 && p;j++){
+ str[j]=p;
+ p=strchr(p,',');
+ if(p){ *p++=0; np=p; }
+ }
+ if(str[0]==NULL)
+ continue;
+
+ nameid=atoi(str[0]);
+ if(nameid<=0 || nameid>=20000)
+ continue;
+ ln++;
+
+ //ID,Name,Jname,Type,Price,Sell,Weight,ATK,DEF,Range,Slot,Job,Gender,Loc,wLV,eLV,View
+ id=itemdb_search(nameid);
+ memcpy(id->name,str[1],24);
+ memcpy(id->jname,str[2],24);
+ id->type=atoi(str[3]);
+ // buy≠sell*2 は item_value_db.txt で指定してください。
+ if (atoi(str[5])) { // sell値を優先とする
+ id->value_buy=atoi(str[5])*2;
+ id->value_sell=atoi(str[5]);
+ } else {
+ id->value_buy=atoi(str[4]);
+ id->value_sell=atoi(str[4])/2;
+ }
+ id->weight=atoi(str[6]);
+ id->atk=atoi(str[7]);
+ id->def=atoi(str[8]);
+ id->range=atoi(str[9]);
+ id->slot=atoi(str[10]);
+ id->class=atoi(str[11]);
+ id->sex=atoi(str[12]);
+ if(id->equip != atoi(str[13])){
+ id->equip=atoi(str[13]);
+ }
+ id->wlv=atoi(str[14]);
+ id->elv=atoi(str[15]);
+ id->look=atoi(str[16]);
+ id->flag.available=1;
+ id->flag.value_notdc=0;
+ id->flag.value_notoc=0;
+ id->view_id=0;
+
+ id->use_script=NULL;
+ id->equip_script=NULL;
+
+ if((p=strchr(np,'{'))==NULL)
+ continue;
+ id->use_script = parse_script(p,lines);
+ if((p=strchr(p+1,'{'))==NULL)
+ continue;
+ id->equip_script = parse_script(p,lines);
+ }
+ fclose(fp);
+ printf("read %s done (count=%d)\n",filename[i],ln);
+ }
+ return 0;
+}
+
+// Removed item_value_db, don't re-add!
+
+/*==========================================
+ * ランダムアイテム出現データの読み込み
+ *------------------------------------------
+ */
+static int itemdb_read_randomitem()
+{
+ FILE *fp;
+ char line[1024];
+ int ln=0;
+ int nameid,i,j;
+ char *str[10],*p;
+
+ const struct {
+ char filename[64];
+ struct random_item_data *pdata;
+ int *pcount,*pdefault;
+ } data[] = {
+ {"db/item_bluebox.txt", blue_box, &blue_box_count, &blue_box_default },
+ {"db/item_violetbox.txt", violet_box, &violet_box_count, &violet_box_default },
+ {"db/item_cardalbum.txt", card_album, &card_album_count, &card_album_default },
+ {"db/item_giftbox.txt", gift_box, &gift_box_count, &gift_box_default },
+ {"db/item_scroll.txt", scroll, &scroll_count, &scroll_default },
+ };
+
+ for(i=0;i<sizeof(data)/sizeof(data[0]);i++){
+ struct random_item_data *pd=data[i].pdata;
+ int *pc=data[i].pcount;
+ int *pdefault=data[i].pdefault;
+ char *fn=data[i].filename;
+
+ *pdefault = 0;
+ if( (fp=fopen(fn,"r"))==NULL ){
+ printf("can't read %s\n",fn);
+ continue;
+ }
+
+ while(fgets(line,1020,fp)){
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ memset(str,0,sizeof(str));
+ for(j=0,p=line;j<3 && p;j++){
+ str[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+
+ if(str[0]==NULL)
+ continue;
+
+ nameid=atoi(str[0]);
+ if(nameid<0 || nameid>=20000)
+ continue;
+ if(nameid == 0) {
+ if(str[2])
+ *pdefault = atoi(str[2]);
+ continue;
+ }
+
+ if(str[2]){
+ pd[ *pc ].nameid = nameid;
+ pd[(*pc)++].per = atoi(str[2]);
+ }
+
+ if(ln >= MAX_RANDITEM)
+ break;
+ ln++;
+ }
+ fclose(fp);
+ printf("read %s done (count=%d)\n",fn,*pc);
+ }
+
+ return 0;
+}
+/*==========================================
+ * アイテム使用可能フラグのオーバーライド
+ *------------------------------------------
+ */
+static int itemdb_read_itemavail(void)
+{
+ FILE *fp;
+ char line[1024];
+ int ln=0;
+ int nameid,j,k;
+ char *str[10],*p;
+
+ if( (fp=fopen("db/item_avail.txt","r"))==NULL ){
+ printf("can't read db/item_avail.txt\n");
+ return -1;
+ }
+
+ while(fgets(line,1020,fp)){
+ struct item_data *id;
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ memset(str,0,sizeof(str));
+ for(j=0,p=line;j<2 && p;j++){
+ str[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+
+ if(str[0]==NULL)
+ continue;
+
+ nameid=atoi(str[0]);
+ if(nameid<0 || nameid>=20000 || !(id=itemdb_exists(nameid)) )
+ continue;
+ k=atoi(str[1]);
+ if(k > 0) {
+ id->flag.available = 1;
+ id->view_id = k;
+ }
+ else
+ id->flag.available = 0;
+ ln++;
+ }
+ fclose(fp);
+ printf("read db/item_avail.txt done (count=%d)\n",ln);
+ return 0;
+}
+
+/*==========================================
+ * アイテムの名前テーブルを読み込む
+ *------------------------------------------
+ */
+static int itemdb_read_itemnametable(void)
+{
+ char *buf,*p;
+ int s;
+
+ buf=grfio_reads("data\\idnum2itemdisplaynametable.txt",&s);
+
+ if(buf==NULL)
+ return -1;
+
+ buf[s]=0;
+ for(p=buf;p-buf<s;){
+ int nameid;
+ char buf2[64];
+
+ if( sscanf(p,"%d#%[^#]#",&nameid,buf2)==2 ){
+
+#ifdef ITEMDB_OVERRIDE_NAME_VERBOSE
+ if( itemdb_exists(nameid) &&
+ strncmp(itemdb_search(nameid)->jname,buf2,24)!=0 ){
+ printf("[override] %d %s => %s\n",nameid
+ ,itemdb_search(nameid)->jname,buf2);
+ }
+#endif
+
+ memcpy(itemdb_search(nameid)->jname,buf2,24);
+ }
+
+ p=strchr(p,10);
+ if(!p) break;
+ p++;
+ }
+ free(buf);
+ printf("read data\\idnum2itemdisplaynametable.txt done.\n");
+
+ return 0;
+}
+#ifdef TXT_ONLY
+/*==========================================
+ * カードイラストのリソース名前テーブルを読み込む
+ *------------------------------------------
+ */
+static int itemdb_read_cardillustnametable(void)
+{
+ char *buf,*p;
+ int s;
+
+ buf=grfio_reads("data\\num2cardillustnametable.txt",&s);
+
+ if(buf==NULL)
+ return -1;
+
+ buf[s]=0;
+ for(p=buf;p-buf<s;){
+ int nameid;
+ char buf2[64];
+
+ if( sscanf(p,"%d#%[^#]#",&nameid,buf2)==2 ){
+ strcat(buf2,".bmp");
+ memcpy(itemdb_search(nameid)->cardillustname,buf2,64);
+// printf("%d %s\n",nameid,itemdb_search(nameid)->cardillustname);
+ }
+
+ p=strchr(p,10);
+ if(!p) break;
+ p++;
+ }
+ free(buf);
+ printf("read data\\num2cardillustnametable.txt done.\n");
+
+ return 0;
+}
+#endif /* TXT_ONLY */
+/*==========================================
+ * 装備制限ファイル読み出し
+ *------------------------------------------
+ */
+static int itemdb_read_noequip(void)
+{
+ FILE *fp;
+ char line[1024];
+ int ln=0;
+ int nameid,j;
+ char *str[32],*p;
+ struct item_data *id;
+
+ if( (fp=fopen("db/item_noequip.txt","r"))==NULL ){
+ printf("can't read db/item_noequip.txt\n");
+ return -1;
+ }
+ while(fgets(line,1020,fp)){
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ memset(str,0,sizeof(str));
+ for(j=0,p=line;j<2 && p;j++){
+ str[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+ if(str[0]==NULL)
+ continue;
+
+ nameid=atoi(str[0]);
+ if(nameid<=0 || nameid>=20000 || !(id=itemdb_exists(nameid)))
+ continue;
+
+ id->flag.no_equip=atoi(str[1]);
+
+ ln++;
+
+ }
+ fclose(fp);
+ printf("read db/item_noequip.txt done (count=%d)\n",ln);
+ return 0;
+}
+#ifndef TXT_ONLY
+
+/*======================================
+* SQL
+*===================================
+*/
+static int itemdb_read_sqldb(void)
+{
+ unsigned short nameid;
+ struct item_data *id;
+ char script[65535 + 2 + 1]; // Maximum length of MySQL TEXT type (65535) + 2 bytes for curly brackets + 1 byte for terminator
+
+ // ----------
+
+ sprintf(tmp_sql, "SELECT * FROM `%s`", item_db_db);
+
+ // Execute the query; if the query execution succeeded...
+ if (mysql_query(&mmysql_handle, tmp_sql) == 0)
+ {
+ sql_res = mysql_store_result(&mmysql_handle);
+
+ // If the storage of the query result succeeded...
+ if (sql_res)
+ {
+ // Parse each row in the query result into sql_row
+ while ((sql_row = mysql_fetch_row(sql_res)))
+ {
+ /* +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+---------------+-----------------+--------------+-------------+------+------------+--------------+
+ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
+ +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+---------------+-----------------+--------------+-------------+------+------------+--------------+
+ | id | name_english | name_japanese | type | price_buy | price_sell | weight | attack | defence | range | slots | equip_jobs | equip_genders | equip_locations | weapon_level | equip_level | view | script_use | script_equip |
+ +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+---------------+-----------------+--------------+-------------+------+------------+--------------+ */
+
+ nameid = atoi(sql_row[0]);
+
+ // If the identifier is not within the valid range, process the next row
+ if (nameid == 0 || nameid >= 20000)
+ {
+ continue;
+ }
+
+ // Insert a new row into the item database
+
+ /*id = calloc(sizeof(struct item_data), 1);
+
+ if (id == NULL)
+ {
+ printf("out of memory : itemdb_read_sqldb\n");
+ exit(1);
+ }
+
+ memset(id, 0, sizeof(struct item_data));
+ numdb_insert(item_db, (int) nameid, id);*/
+
+ // ----------
+ id=itemdb_search(nameid);
+
+ memcpy(id->name, sql_row[1], 25);
+ memcpy(id->jname, sql_row[2], 25);
+
+ id->type = atoi(sql_row[3]);
+
+ // If price_buy is not NULL and price_sell is not NULL...
+ if ((sql_row[4] != NULL) && (sql_row[5] != NULL))
+ {
+ id->value_buy = atoi(sql_row[4]);
+ id->value_sell = atoi(sql_row[5]);
+ }
+ // If price_buy is not NULL and price_sell is NULL...
+ else if ((sql_row[4] != NULL) && (sql_row[5] == NULL))
+ {
+ id->value_buy = atoi(sql_row[4]);
+ id->value_sell = atoi(sql_row[4]) / 2;
+ }
+ // If price_buy is NULL and price_sell is not NULL...
+ else if ((sql_row[4] == NULL) && (sql_row[5] != NULL))
+ {
+ id->value_buy = atoi(sql_row[5]) * 2;
+ id->value_sell = atoi(sql_row[5]);
+ }
+ // If price_buy is NULL and price_sell is NULL...
+ if ((sql_row[4] == NULL) && (sql_row[5] == NULL))
+ {
+ id->value_buy = 0;
+ id->value_sell = 0;
+ }
+
+ id->weight = atoi(sql_row[6]);
+
+ id->atk = (sql_row[7] != NULL) ? atoi(sql_row[7]) : 0;
+ id->def = (sql_row[8] != NULL) ? atoi(sql_row[8]) : 0;
+ id->range = (sql_row[9] != NULL) ? atoi(sql_row[9]) : 0;
+ id->slot = (sql_row[10] != NULL) ? atoi(sql_row[10]) : 0;
+ id->class = (sql_row[11] != NULL) ? atoi(sql_row[11]) : 0;
+ id->sex = (sql_row[12] != NULL) ? atoi(sql_row[12]) : 0;
+ id->equip = (sql_row[13] != NULL) ? atoi(sql_row[13]) : 0;
+ id->wlv = (sql_row[14] != NULL) ? atoi(sql_row[14]) : 0;
+ id->elv = (sql_row[15] != NULL) ? atoi(sql_row[15]) : 0;
+ id->look = (sql_row[16] != NULL) ? atoi(sql_row[16]) : 0;
+
+ id->view_id = 0;
+
+ // ----------
+
+ if (sql_row[17] != NULL)
+ {
+ if (sql_row[17][0] == '{')
+ id->use_script = parse_script(sql_row[17], 0);
+ else {
+ sprintf(script, "{%s}", sql_row[17]);
+ id->use_script = parse_script(script, 0);
+ }
+ }
+ else
+ {
+ id->use_script = NULL;
+ }
+
+ if (sql_row[18] != NULL)
+ {
+ if (sql_row[18][0] == '{')
+ id->equip_script = parse_script(sql_row[18], 0);
+ else {
+ sprintf(script, "{%s}", sql_row[18]);
+ id->equip_script = parse_script(script, 0);
+ }
+ }
+ else
+ {
+ id->equip_script = NULL;
+ }
+
+ // ----------
+
+ id->flag.available = 1;
+ id->flag.value_notdc = 0;
+ id->flag.value_notoc = 0;
+ }
+
+ // If the retrieval failed, output an error
+ if (mysql_errno(&mmysql_handle))
+ {
+ printf("Database server error (retrieving rows from %s): %s\n", item_db_db, mysql_error(&mmysql_handle));
+ }
+
+ printf("read %s done (count = %lu)\n", item_db_db, (unsigned long) mysql_num_rows(sql_res));
+ }
+ else
+ {
+ printf("MySQL error (storing query result for %s): %s\n", item_db_db, mysql_error(&mmysql_handle));
+ }
+
+ // Free the query result
+ mysql_free_result(sql_res);
+ }
+ else
+ {
+ printf("Database server error (executing query for %s): %s\n", item_db_db, mysql_error(&mmysql_handle));
+ }
+
+ return 0;
+}
+
+#endif /* not TXT_ONLY */
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static int itemdb_final(void *key,void *data,va_list ap)
+{
+ struct item_data *id;
+
+ nullpo_retr(0, id=data);
+
+ if(id->use_script)
+ free(id->use_script);
+ if(id->equip_script)
+ free(id->equip_script);
+ free(id);
+
+ return 0;
+}
+
+void itemdb_reload(void)
+{
+ /*
+
+ <empty item databases>
+ itemdb_read();
+
+ */
+
+ do_init_itemdb();
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void do_final_itemdb(void)
+{
+ if(item_db){
+ numdb_final(item_db,itemdb_final);
+ item_db=NULL;
+ }
+}
+
+/*
+static FILE *dfp;
+static int itemdebug(void *key,void *data,va_list ap){
+// struct item_data *id=(struct item_data *)data;
+ fprintf(dfp,"%6d",(int)key);
+ return 0;
+}
+void itemdebugtxt()
+{
+ dfp=fopen("itemdebug.txt","wt");
+ numdb_foreach(item_db,itemdebug);
+ fclose(dfp);
+}
+*/
+#ifdef TXT_ONLY
+/*====================================
+ * Removed item_value_db, don't re-add
+ *------------------------------------
+ */
+static void itemdb_read(void)
+{
+ itemdb_read_itemslottable();
+ itemdb_readdb();
+ itemdb_read_randomitem();
+ itemdb_read_itemavail();
+ itemdb_read_noequip();
+ itemdb_read_cardillustnametable();
+ if (!battle_config.item_name_override_grffile)
+ itemdb_read_itemnametable();
+}
+#endif /* TXT_ONLY */
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int do_init_itemdb(void)
+{
+ item_db = numdb_init();
+
+ itemdb_read();
+
+ return 0;
+}
diff --git a/src/map/itemdb.h b/src/map/itemdb.h
new file mode 100644
index 000000000..05ecc572f
--- /dev/null
+++ b/src/map/itemdb.h
@@ -0,0 +1,84 @@
+// $Id: itemdb.h,v 1.3 2004/09/25 05:32:18 MouseJstr Exp $
+#ifndef _ITEMDB_H_
+#define _ITEMDB_H_
+
+#include "map.h"
+
+struct item_data {
+ int nameid;
+ char name[24],jname[24];
+ char prefix[24],suffix[24];
+ char cardillustname[64];
+ int value_buy;
+ int value_sell;
+ int type;
+ int class;
+ int sex;
+ int equip;
+ int weight;
+ int atk;
+ int def;
+ int range;
+ int slot;
+ int look;
+ int elv;
+ int wlv;
+ int refine;
+ char *use_script; // 回復とかも全部この中でやろうかなと
+ char *equip_script; // 攻撃,防御の属性設定もこの中で可能かな?
+ struct {
+ unsigned available : 1;
+ unsigned value_notdc : 1;
+ unsigned value_notoc : 1;
+ unsigned no_equip : 3;
+ unsigned no_drop : 1;
+ unsigned no_use : 1;
+ } flag;
+ int view_id;
+};
+
+struct random_item_data {
+ int nameid;
+ int per;
+};
+
+struct item_data* itemdb_searchname(const char *name);
+struct item_data* itemdb_search(int nameid);
+struct item_data* itemdb_exists(int nameid);
+#define itemdb_type(n) itemdb_search(n)->type
+#define itemdb_atk(n) itemdb_search(n)->atk
+#define itemdb_def(n) itemdb_search(n)->def
+#define itemdb_look(n) itemdb_search(n)->look
+#define itemdb_weight(n) itemdb_search(n)->weight
+#define itemdb_equip(n) itemdb_search(n)->equip
+#define itemdb_usescript(n) itemdb_search(n)->use_script
+#define itemdb_equipscript(n) itemdb_search(n)->equip_script
+#define itemdb_wlv(n) itemdb_search(n)->wlv
+#define itemdb_range(n) itemdb_search(n)->range
+#define itemdb_slot(n) itemdb_search(n)->slot
+#define itemdb_available(n) (itemdb_exists(n) && itemdb_search(n)->flag.available)
+#define itemdb_viewid(n) (itemdb_search(n)->view_id)
+
+int itemdb_searchrandomid(int flags);
+
+#define itemdb_value_buy(n) itemdb_search(n)->value_buy
+#define itemdb_value_sell(n) itemdb_search(n)->value_sell
+#define itemdb_value_notdc(n) itemdb_search(n)->flag.value_notdc
+#define itemdb_value_notoc(n) itemdb_search(n)->flag.value_notoc
+
+int itemdb_isequip(int);
+int itemdb_isequip2(struct item_data *);
+int itemdb_isequip3(int);
+int itemdb_isdropable(int nameid);
+
+// itemdb_equipマクロとitemdb_equippointとの違いは
+// 前者が鯖側dbで定義された値そのものを返すのに対し
+// 後者はsessiondataを考慮した鞍側での装備可能場所
+// すべての組み合わせを返す
+
+void itemdb_reload(void);
+
+void do_final_itemdb(void);
+int do_init_itemdb(void);
+
+#endif
diff --git a/src/map/log.c b/src/map/log.c
new file mode 100644
index 000000000..b8997a7df
--- /dev/null
+++ b/src/map/log.c
@@ -0,0 +1,243 @@
+// Logging functions by Azndragon & Codemaster
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "map.h"
+#include "nullpo.h"
+#include "log.h"
+
+struct Log_Config log_config;
+
+int log_branch(struct map_session_data *sd)
+{
+ #ifndef TXT_ONLY
+ nullpo_retr(0, sd);
+ sprintf(tmp_sql, "INSERT INTO `%s` (`branch_date`, `account_id`, `char_id`, `char_name`, `map`) VALUES (NOW(), '%d', '%d', '%s', '%s')", log_config.log_branch_db, sd->status.account_id, sd->status.char_id, sd->status.name, sd->mapname);
+ if(mysql_query(&mmysql_handle, tmp_sql))
+ printf("DB server Error - %s\n",mysql_error(&mmysql_handle));
+ #endif
+ return 0;
+}
+
+int log_drop(struct map_session_data *sd, int monster_id, int *log_drop)
+{
+ #ifndef TXT_ONLY
+ nullpo_retr(0, sd);
+ sprintf(tmp_sql, "INSERT INTO `%s` (`drop_date`, `kill_char_id`, `monster_id`, `item1`, `item2`, `item3`, `item4`, `item5`, `item6`, `item7`, `item8`, `map`) VALUES (NOW(), '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s') ", log_config.log_drop_db, sd->status.char_id, monster_id, log_drop[0], log_drop[1], log_drop[2], log_drop[3], log_drop[4], log_drop[5], log_drop[6], log_drop[7], sd->mapname);
+ if(mysql_query(&mmysql_handle, tmp_sql))
+ printf("DB server Error - %s\n",mysql_error(&mmysql_handle));
+ #endif
+ return 0;
+}
+
+int log_mvpdrop(struct map_session_data *sd, int monster_id, int *log_mvp)
+{
+ #ifndef TXT_ONLY
+ nullpo_retr(0, sd);
+ sprintf(tmp_sql, "INSERT INTO `%s` (`mvp_date`, `kill_char_id`, `monster_id`, `prize`, `mvpexp`, `map`) VALUES (NOW(), '%d', '%d', '%d', '%d', '%s') ", log_config.log_mvpdrop_db, sd->status.char_id, monster_id, log_mvp[0], log_mvp[1], sd->mapname);
+ if(mysql_query(&mmysql_handle, tmp_sql))
+ printf("DB server Error - %s\n",mysql_error(&mmysql_handle));
+ #endif
+ return 0;
+}
+
+int log_present(struct map_session_data *sd, int source_type, int nameid)
+{
+ #ifndef TXT_ONLY
+ nullpo_retr(0, sd);
+ sprintf(tmp_sql, "INSERT INTO `%s` (`present_date`, `src_id`, `account_id`, `char_id`, `char_name`, `nameid`, `map`) VALUES (NOW(), '%d', '%d', '%d', '%s', '%d', '%s') ", log_config.log_present_db, source_type, sd->status.account_id, sd->status.char_id, sd->status.name, nameid, sd->mapname);
+ if(mysql_query(&mmysql_handle, tmp_sql))
+ printf("DB server Error - %s\n",mysql_error(&mmysql_handle));
+ #endif
+ return 0;
+}
+
+int log_produce(struct map_session_data *sd, int nameid, int slot1, int slot2, int slot3, int success)
+{
+ #ifndef TXT_ONLY
+ nullpo_retr(0, sd);
+ sprintf(tmp_sql, "INSERT INTO `%s` (`produce_date`, `account_id`, `char_id`, `char_name`, `nameid`, `slot1`, `slot2`, `slot3`, `map`, `success`) VALUES (NOW(), '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%s', '%d') ", log_config.log_produce_db, sd->status.account_id, sd->status.char_id, sd->status.name, nameid, slot1, slot2, slot3, sd->mapname, success);
+ if(mysql_query(&mmysql_handle, tmp_sql))
+ printf("DB server Error - %s\n",mysql_error(&mmysql_handle));
+ #endif
+ return 0;
+}
+
+int log_refine(struct map_session_data *sd, int n, int success)
+{
+ #ifndef TXT_ONLY
+ int log_card[4];
+ int item_level;
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if(success == 0)
+ item_level = 0;
+ else
+ item_level = sd->status.inventory[n].refine + 1;
+
+ for(i=0;i<4;i++)
+ log_card[i] = sd->status.inventory[n].card[i];
+
+ sprintf(tmp_sql, "INSERT INTO `%s` (`refine_date`, `account_id`, `char_id`, `char_name`, `nameid`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`, `success`, `item_level`) VALUES (NOW(), '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%s', '%d', '%d')", log_config.log_refine_db, sd->status.account_id, sd->status.char_id, sd->status.name, sd->status.inventory[n].nameid, sd->status.inventory[n].refine, log_card[0], log_card[1], log_card[2], log_card[3], sd->mapname, success, item_level);
+ if(mysql_query(&mmysql_handle, tmp_sql))
+ printf("DB server Error - %s\n",mysql_error(&mmysql_handle));
+ #endif
+ return 0;
+}
+
+int log_trade(struct map_session_data *sd, struct map_session_data *target_sd, int n,int amount)
+{
+ #ifndef TXT_ONLY
+ int log_nameid, log_amount, log_refine, log_card[4];
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if(sd->status.inventory[n].nameid==0 || amount <= 0 || sd->status.inventory[n].amount<amount || sd->inventory_data[n] == NULL)
+ return 1;
+
+ if(sd->status.inventory[n].amount>=0)
+ {
+ log_nameid = sd->status.inventory[n].nameid;
+ log_amount = sd->status.inventory[n].amount;
+ log_refine = sd->status.inventory[n].refine;
+
+ for(i=0;i<4;i++)
+ log_card[i] = sd->status.inventory[n].card[i];
+
+ sprintf(tmp_sql, "INSERT INTO `%s` (`trade_date`, `src_account_id`, `src_char_id`, `src_char_name`, `des_account_id`, `des_char_id`, `des_char_name`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`) VALUES (NOW(), '%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s')", log_config.log_trade_db, sd->status.account_id, sd->status.char_id, sd->status.name, target_sd->status.account_id, target_sd->status.char_id, target_sd->status.name, log_nameid, log_amount, log_refine, log_card[0], log_card[1], log_card[2], log_card[3], sd->mapname);
+ if(mysql_query(&mmysql_handle, tmp_sql))
+ printf("DB server Error - %s\n",mysql_error(&mmysql_handle));
+ }
+ #endif
+ return 0;
+}
+
+int log_vend(struct map_session_data *sd,struct map_session_data *vsd,int n,int amount, int zeny)
+{
+ #ifndef TXT_ONLY
+ int log_nameid, log_amount, log_refine, log_card[4];
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if(sd->status.inventory[n].nameid==0 || amount <= 0 || sd->status.inventory[n].amount<amount || sd->inventory_data[n] == NULL)
+ return 1;
+
+ if(sd->status.inventory[n].amount>=0)
+ {
+ log_nameid = sd->status.inventory[n].nameid;
+ log_amount = sd->status.inventory[n].amount;
+ log_refine = sd->status.inventory[n].refine;
+
+ for(i=0;i<4;i++)
+ log_card[i] = sd->status.inventory[n].card[i];
+
+ sprintf(tmp_sql, "INSERT INTO `%s` (`vend_date`, `vend_account_id`, `vend_char_id`, `vend_char_name`, `buy_account_id`, `buy_char_id`, `buy_char_name`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`, `zeny`) VALUES (NOW(), '%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s', '%d')", log_config.log_vend_db, sd->status.account_id, sd->status.char_id, sd->status.name, vsd->status.account_id, vsd->status.char_id, vsd->status.name, log_nameid, log_amount, log_refine, log_card[0], log_card[1], log_card[2], log_card[3], sd->mapname, zeny);
+ if(mysql_query(&mmysql_handle, tmp_sql))
+ printf("DB server Error - %s\n",mysql_error(&mmysql_handle));
+ }
+ #endif
+ return 0;
+}
+
+int log_zeny(struct map_session_data *sd, struct map_session_data *target_sd,int amount)
+{
+ #ifndef TXT_ONLY
+ nullpo_retr(0, sd);
+
+ sprintf(tmp_sql,"INSERT INTO `%s` (`trade_date`, `src_account_id`, `src_char_id`, `src_char_name`, `des_account_id`, `des_char_id`, `des_char_name`, `map`, `zeny`) VALUES (NOW(), '%d', '%d', '%s', '%d', '%d', '%s', '%s', '%d')", log_config.log_trade_db, sd->status.account_id, sd->status.char_id, sd->status.name, target_sd->status.account_id, target_sd->status.char_id, target_sd->status.name, sd->mapname, sd->deal_zeny);
+ if(mysql_query(&mmysql_handle, tmp_sql))
+ printf("DB server Error - %s\n",mysql_error(&mmysql_handle));
+ #endif
+ return 0;
+}
+
+int log_config_read(char *cfgName)
+{
+ char line[1024], w1[1024], w2[1024];
+ FILE *fp;
+
+ if((fp = fopen(cfgName, "r")) == NULL)
+ {
+ printf("Log configuration file not found at: %s\n", cfgName);
+ return 1;
+ }
+
+ while(fgets(line, sizeof(line) -1, fp))
+ {
+ if(line[0] == '/' && line[1] == '/')
+ continue;
+
+ if(sscanf(line, "%[^:]: %[^\r\n]", w1, w2) == 2)
+ {
+ if(strcmpi(w1,"log_branch") == 0) {
+ log_config.branch = (atoi(w2));
+ } else if(strcmpi(w1,"log_drop") == 0) {
+ log_config.drop = (atoi(w2));
+ } else if(strcmpi(w1,"log_mvpdrop") == 0) {
+ log_config.mvpdrop = (atoi(w2));
+ } else if(strcmpi(w1,"log_present") == 0) {
+ log_config.present = (atoi(w2));
+ } else if(strcmpi(w1,"log_produce") == 0) {
+ log_config.produce = (atoi(w2));
+ } else if(strcmpi(w1,"log_refine") == 0) {
+ log_config.refine = (atoi(w2));
+ } else if(strcmpi(w1,"log_trade") == 0) {
+ log_config.trade = (atoi(w2));
+ } else if(strcmpi(w1,"log_vend") == 0) {
+ log_config.vend = (atoi(w2));
+ } else if(strcmpi(w1,"log_zeny") == 0) {
+ if(log_config.trade != 1)
+ log_config.zeny = 0;
+ else
+ log_config.zeny = (atoi(w2));
+ }
+
+ else if(strcmpi(w1, "log_branch_db") == 0) {
+ strcpy(log_config.log_branch_db, w2);
+ if(log_config.branch == 1)
+ printf("Logging Dead Branch Usage to table `%s`\n", w2);
+ } else if(strcmpi(w1, "log_drop_db") == 0) {
+ strcpy(log_config.log_drop_db, w2);
+ if(log_config.drop == 1)
+ printf("Logging Item Drops to table `%s`\n", w2);
+ } else if(strcmpi(w1, "log_mvpdrop_db") == 0) {
+ strcpy(log_config.log_mvpdrop_db, w2);
+ if(log_config.mvpdrop == 1)
+ printf("Logging MVP Drops to table `%s`\n", w2);
+ } else if(strcmpi(w1, "log_present_db") == 0) {
+ strcpy(log_config.log_present_db, w2);
+ if(log_config.present == 1)
+ printf("Logging Present Usage & Results to table `%s`\n", w2);
+ } else if(strcmpi(w1, "log_produce_db") == 0) {
+ strcpy(log_config.log_produce_db, w2);
+ if(log_config.produce == 1)
+ printf("Logging Producing to table `%s`\n", w2);
+ } else if(strcmpi(w1, "log_refine_db") == 0) {
+ strcpy(log_config.log_refine_db, w2);
+ if(log_config.refine == 1)
+ printf("Logging Refining to table `%s`\n", w2);
+ } else if(strcmpi(w1, "log_trade_db") == 0) {
+ strcpy(log_config.log_trade_db, w2);
+ if(log_config.trade == 1)
+ {
+ printf("Logging Item Trades");
+ if(log_config.zeny == 1)
+ printf("and Zeny Trades");
+ printf(" to table `%s`\n", w2);
+ }
+ } else if(strcmpi(w1, "log_vend_db") == 0) {
+ strcpy(log_config.log_vend_db, w2);
+ if(log_config.vend == 1)
+ printf("Logging Vending to table `%s`\n", w2);
+ }
+ }
+ }
+
+ fclose(fp);
+ return 0;
+}
diff --git a/src/map/log.h b/src/map/log.h
new file mode 100644
index 000000000..7047d980c
--- /dev/null
+++ b/src/map/log.h
@@ -0,0 +1,27 @@
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#ifndef TXT_ONLY
+
+extern char db_server_logdb[32];
+
+#endif //NOT TXT_ONLY
+
+int log_branch(struct map_session_data *sd);
+int log_drop(struct map_session_data *sd, int monster_id, int *log_drop);
+int log_mvpdrop(struct map_session_data *sd, int monster_id, int *log_mvp);
+int log_present(struct map_session_data *sd, int source_type, int nameid);
+int log_produce(struct map_session_data *sd, int nameid, int slot1, int slot2, int slot3, int success);
+int log_refine(struct map_session_data *sd, int n, int success);
+int log_trade(struct map_session_data *sd,struct map_session_data *target_sd,int n,int amount);
+int log_vend(struct map_session_data *sd,struct map_session_data *vsd,int n,int amount,int zeny);
+int log_zeny(struct map_session_data *sd, struct map_session_data *target_sd,int amount);
+
+int log_config_read(char *cfgName);
+
+extern struct Log_Config {
+ int branch, drop, mvpdrop, present, produce, refine, trade, vend, zeny;
+ char log_branch_db[32], log_drop_db[32], log_mvpdrop_db[32], log_present_db[32], log_produce_db[32], log_refine_db[32], log_trade_db[32], log_vend_db[32];
+} log_config;
+
+#endif
diff --git a/src/map/mail.c b/src/map/mail.c
new file mode 100644
index 000000000..c6155a04d
--- /dev/null
+++ b/src/map/mail.c
@@ -0,0 +1,324 @@
+// Mail System for eAthena SQL
+// Created by Valaris
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "socket.h"
+#include "timer.h"
+#include "nullpo.h"
+
+#include "map.h"
+#include "clif.h"
+#include "chrif.h"
+#include "intif.h"
+#include "pc.h"
+#include "mail.h"
+
+char mail_db[32] = "mail";
+
+int MAIL_CHECK_TIME = 120000;
+int mail_timer;
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+int mail_check(struct map_session_data *sd,int type)
+{
+ int i=0,new=0,priority=0;
+ char message[50];
+
+ if(sd==NULL)
+ return 0;
+
+ sprintf(tmp_msql,"SELECT `message_id`,`to_account_id`,`from_char_name`,`read_flag`,`priority`,`check_flag` FROM `%s` WHERE `to_account_id` = \"%d\" ORDER by `message_id`", mail_db, sd->status.account_id);
+
+ if (mysql_query(&mail_handle, tmp_msql)) {
+ printf("Database server error (executing query for %s): %s\n", mail_db, mysql_error(&mail_handle));
+ return 0;
+ }
+
+ mail_res = mysql_store_result(&mail_handle);
+ if(mail_res) {
+ if (mysql_num_rows(mail_res) == 0) {
+ clif_displaymessage(sd->fd,"You have no messages.");
+ mysql_free_result(mail_res);
+ return 0;
+ }
+
+ while ((mail_row = mysql_fetch_row(mail_res))) {
+ i++;
+
+ if(!atoi(mail_row[5])) {
+ sprintf(tmp_msql,"UPDATE `%s` SET `check_flag`='1' WHERE `message_id`= \"%d\"", mail_db, atoi(mail_row[0]));
+ if(mysql_query(&mail_handle, tmp_msql) ) {
+ printf("DB server Error (update Read `%s`)- %s\n", mail_db, mysql_error(&mail_handle) );
+ }
+ }
+
+ if(!atoi(mail_row[3])) {
+ new++;
+ if(atoi(mail_row[4]))
+ priority++;
+ if(type==2 || type==3) {
+ if(atoi(mail_row[4])) {
+ sprintf(message, "%d - From : %s (New - Priority)", i, mail_row[2]);
+ clif_displaymessage(sd->fd, message);
+ }
+
+ else {
+ sprintf(message, "%d - From : %s (New)", i, mail_row[2]);
+ clif_displaymessage(sd->fd, message);
+ }
+ }
+ }
+
+ else if(type==2){
+ sprintf(message, "%d - From : %s", i, mail_row[2]);
+ clif_displaymessage(sd->fd, message);
+ }
+
+ }
+
+ mysql_free_result(mail_res);
+
+ } else {
+ printf("MySQL error (storing query result for %s): %s\n", mail_db, mysql_error(&mail_handle));
+ return 0;
+ }
+
+ if(i>0 && new>0 && type==1) {
+ sprintf(message, "You have %d new messages.", new);
+ clif_displaymessage(sd->fd, message);
+ }
+ if(i>0 && new>0 && priority>0 && type==1) {
+ sprintf(message, "You have %d unread priority messages.", priority);
+ clif_displaymessage(sd->fd, message);
+ }
+ if(!new) {
+ clif_displaymessage(sd->fd, "You have no new messages.");
+ }
+
+ return 0;
+}
+
+int mail_read(struct map_session_data *sd, int message_id)
+{
+
+ char message[80];
+
+ if(sd==NULL)
+ return 0;
+
+ sprintf(tmp_msql,"SELECT `message_id`,`to_account_id`,`from_char_name`,`message`,`read_flag`,`priority`,`check_flag` from `%s` WHERE `to_account_id` = \"%d\" ORDER by `message_id` LIMIT %d, 1",mail_db,sd->status.account_id,message_id-1);
+
+ if (mysql_query(&mail_handle, tmp_msql)) {
+ printf("Database server error (executing query for %s): %s\n", mail_db, mysql_error(&mail_handle));
+ return 0;
+ }
+
+ mail_res = mysql_store_result(&mail_handle);
+ if(mail_res) {
+ if (mysql_num_rows(mail_res) == 0) {
+ mysql_free_result(mail_res);
+ clif_displaymessage(sd->fd, "Message not found.");
+ return 0;
+ }
+
+ if ((mail_row = mysql_fetch_row(mail_res))) {
+
+ if(!atoi(mail_row[6])) {
+ sprintf(tmp_msql,"UPDATE `%s` SET `check_flag`='1' WHERE `message_id`= \"%d\"", mail_db, atoi(mail_row[0]));
+ if(mysql_query(&mail_handle, tmp_msql) ) {
+ printf("DB server Error (update Read `%s`)- %s\n", mail_db, mysql_error(&mail_handle) );
+ }
+ }
+
+ sprintf(message, "Reading message from %s", mail_row[2]);
+ clif_displaymessage(sd->fd, message);
+
+ sprintf(message, "%s", mail_row[3]);
+ clif_displaymessage(sd->fd, message);
+
+ sprintf(tmp_msql,"UPDATE `%s` SET `read_flag`='1' WHERE `message_id`= \"%d\"", mail_db, atoi(mail_row[0]));
+ if(mysql_query(&mail_handle, tmp_msql) ) {
+ printf("DB server Error (update Read `%s`)- %s\n", mail_db, mysql_error(&mail_handle) );
+ }
+ }
+
+ mysql_free_result(mail_res);
+
+ } else {
+ printf("MySQL error (storing query result for %s): %s\n", mail_db, mysql_error(&mail_handle));
+ return 0;
+ }
+
+ return 0;
+}
+
+int mail_delete(struct map_session_data *sd, int message_id)
+{
+ if(sd==NULL)
+ return 0;
+
+ sprintf(tmp_msql,"SELECT `message_id`,`to_account_id`,`read_flag`,`priority`,`check_flag` from `%s` WHERE `to_account_id` = \"%d\" ORDER by `message_id` LIMIT %d, 1",mail_db,sd->status.account_id,message_id-1);
+
+ if (mysql_query(&mail_handle, tmp_msql)) {
+ printf("Database server error (executing query for %s): %s\n", mail_db, mysql_error(&mail_handle));
+ return 0;
+ }
+
+ mail_res = mysql_store_result(&mail_handle);
+ if(mail_res) {
+ if (mysql_num_rows(mail_res) == 0) {
+ mysql_free_result(mail_res);
+ clif_displaymessage(sd->fd, "Message not found.");
+ return 0;
+ }
+
+ if ((mail_row = mysql_fetch_row(mail_res))) {
+ if(!atoi(mail_row[2]) && atoi(mail_row[3])) {
+ mysql_free_result(mail_res);
+ clif_displaymessage(sd->fd,"Cannot delete unread priority mail.");
+ return 0;
+ }
+ if(!atoi(mail_row[4])) {
+ mysql_free_result(mail_res);
+ clif_displaymessage(sd->fd,"You have recieved new mail, use @listmail before deleting.");
+ return 0;
+ }
+ sprintf(tmp_msql,"DELETE FROM `%s` WHERE `message_id` = \"%d\"", mail_db, atoi(mail_row[0]));
+ if(mysql_query(&mail_handle, tmp_msql) ) {
+ mysql_free_result(mail_res);
+ printf("DB server Error (update Read `%s`)- %s\n", mail_db, mysql_error(&mail_handle) );
+ return 0;
+ }
+ else clif_displaymessage(sd->fd,"Message deleted.");
+ }
+
+ mysql_free_result(mail_res);
+
+ } else {
+ printf("MySQL error (delete query result for %s): %s\n", mail_db, mysql_error(&mail_handle));
+ return 0;
+ }
+
+ return 0;
+}
+
+int mail_send(struct map_session_data *sd, char *name, char *message, int flag)
+{
+ if(sd==NULL)
+ return 0;
+
+ if(pc_isGM(sd) < 80 && sd->mail_counter > 0) {
+ clif_displaymessage(sd->fd,"You must wait 10 minutes before sending another message");
+ return 0;
+ }
+
+ if(strcmp(name,"*")==0) {
+ if(pc_isGM(sd) < 80) {
+ clif_displaymessage(sd->fd, "Access Denied.");
+ return 0;
+ }
+ else
+ sprintf(tmp_msql,"SELECT DISTINCT `account_id` FROM `%s` WHERE `account_id` <> '%d' ORDER BY `account_id`", char_db, sd->status.account_id);
+ }
+ else
+ sprintf(tmp_msql,"SELECT `account_id`,`name` FROM `%s` WHERE `name` = \"%s\"", char_db, name);
+
+ if (mysql_query(&mail_handle, tmp_msql)) {
+ printf("Database server error (executing query for %s): %s\n", char_db, mysql_error(&mail_handle));
+ return 0;
+ }
+
+ mail_res = mysql_store_result(&mail_handle);
+ if(mail_res) {
+ if (mysql_num_rows(mail_res) == 0) {
+ mysql_free_result(mail_res);
+ clif_displaymessage(sd->fd,"Character does not exist.");
+ return 0;
+ }
+
+ while ((mail_row = mysql_fetch_row(mail_res))) {
+ if(strcmp(name,"*")==0) {
+ sprintf(tmp_msql, "INSERT INTO `%s` (`to_account_id`,`from_account_id`,`from_char_name`,`message`,`priority`)"
+ " VALUES ('%d', '%d', '%s', '%s', '%d')",mail_db, atoi(mail_row[0]), sd->status.account_id, sd->status.name, message, flag);
+ }
+ else {
+ sprintf(tmp_msql, "INSERT INTO `%s` (`to_account_id`,`to_char_name`,`from_account_id`,`from_char_name`,`message`,`priority`)"
+ " VALUES ('%d', '%s', '%d', '%s', '%s', '%d')",mail_db, atoi(mail_row[0]), mail_row[1], sd->status.account_id, sd->status.name, message, flag);
+ if(pc_isGM(sd) < 80)
+ sd->mail_counter=5;
+ }
+
+ if(mysql_query(&mail_handle, tmp_msql) ) {
+ mysql_free_result(mail_res);
+ printf("DB server Error (insert `mail_db`)- %s\n", mysql_error(&mail_handle) );
+ return 0;
+ }
+
+ }
+ }
+
+ clif_displaymessage(sd->fd,"Mail has been sent.");
+
+ return 0;
+}
+
+int mail_check_timer(int tid,unsigned int tick,int id,int data)
+{
+ struct map_session_data *sd = NULL;
+ int i;
+
+ if(mail_timer != tid)
+ return 0;
+
+ sprintf(tmp_msql,"SELECT DISTINCT `to_account_id` FROM `%s` WHERE `read_flag` = '0' AND `check_flag` = '0'", mail_db);
+
+ if (mysql_query(&mail_handle, tmp_msql)) {
+ printf("Database server error (executing query for %s): %s\n", char_db, mysql_error(&mail_handle));
+ mail_timer=add_timer(gettick()+MAIL_CHECK_TIME,mail_check_timer,0,0);
+ return 0;
+ }
+
+ mail_res = mysql_store_result(&mail_handle);
+
+ if (mail_res) {
+
+ if (mysql_num_rows(mail_res) == 0) {
+ mysql_free_result(mail_res);
+ mail_timer=add_timer(gettick()+MAIL_CHECK_TIME,mail_check_timer,0,0);
+ return 0;
+ }
+
+ while ((mail_row = mysql_fetch_row(mail_res))) {
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (sd = session[i]->session_data) && sd->state.auth){
+ if(pc_isGM(sd) < 80 && sd->mail_counter > 0)
+ sd->mail_counter--;
+ if(sd->status.account_id==atoi(mail_row[0]))
+ clif_displaymessage(sd->fd, "You have new mail.");
+ }
+ }
+ }
+ }
+
+ sprintf(tmp_msql,"UPDATE `%s` SET `check_flag`='1' WHERE `check_flag`= '0' ", mail_db);
+ if(mysql_query(&mail_handle, tmp_msql) ) {
+ printf("DB server Error (update Read `%s`)- %s\n", mail_db, mysql_error(&mail_handle) );
+ }
+
+ mail_timer=add_timer(gettick()+MAIL_CHECK_TIME,mail_check_timer,0,0);
+ return 0;
+}
+
+int do_init_mail(void)
+{
+ add_timer_func_list(mail_check_timer,"mail_check_timer");
+ mail_timer=add_timer(gettick()+MAIL_CHECK_TIME,mail_check_timer,0,0);
+ return 0;
+}
+
diff --git a/src/map/mail.h b/src/map/mail.h
new file mode 100644
index 000000000..cfa86c6bb
--- /dev/null
+++ b/src/map/mail.h
@@ -0,0 +1,9 @@
+// Mail System for eAthena
+// Created by Valaris
+
+int mail_check(struct map_session_data *sd, int type);
+int mail_read(struct map_session_data *sd, int message_id);
+int mail_delete(struct map_session_data *sd, int message_id);
+int mail_send(struct map_session_data *sd, char *name, char *message, int flag);
+
+int do_init_mail(void);
diff --git a/src/map/map.c b/src/map/map.c
new file mode 100644
index 000000000..217f36c88
--- /dev/null
+++ b/src/map/map.c
@@ -0,0 +1,2208 @@
+// $Id: map.c,v 1.6 2004/09/25 17:37:01 MouseJstr Exp $
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#ifdef _WIN32
+#include <winsock.h>
+#else
+#include <netdb.h>
+#endif
+
+#include "core.h"
+#include "timer.h"
+#include "db.h"
+#include "grfio.h"
+#include "malloc.h"
+
+#include "map.h"
+#include "chrif.h"
+#include "clif.h"
+#include "intif.h"
+#include "npc.h"
+#include "pc.h"
+#include "mob.h"
+#include "chat.h"
+#include "itemdb.h"
+#include "storage.h"
+#include "skill.h"
+#include "trade.h"
+#include "party.h"
+#include "battle.h"
+#include "script.h"
+#include "guild.h"
+#include "pet.h"
+#include "atcommand.h"
+#include "nullpo.h"
+#include "socket.h"
+#include "log.h"
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+unsigned long ticks = 0; // by MC Cameri
+
+#ifndef TXT_ONLY
+
+#include "mail.h" // mail system [Valaris]
+
+MYSQL mmysql_handle;
+MYSQL_RES* sql_res ;
+MYSQL_ROW sql_row ;
+char tmp_sql[65535]="";
+
+MYSQL lmysql_handle;
+MYSQL_RES* lsql_res ;
+MYSQL_ROW lsql_row ;
+char tmp_lsql[65535]="";
+
+MYSQL mail_handle; // mail system [Valaris]
+MYSQL_RES* mail_res ;
+MYSQL_ROW mail_row ;
+char tmp_msql[65535]="";
+
+int map_server_port = 3306;
+char map_server_ip[16] = "127.0.0.1";
+char map_server_id[32] = "ragnarok";
+char map_server_pw[32] = "ragnarok";
+char map_server_db[32] = "ragnarok";
+int db_use_sqldbs = 0;
+
+int login_server_port = 3306;
+char login_server_ip[16] = "127.0.0.1";
+char login_server_id[32] = "ragnarok";
+char login_server_pw[32] = "ragnarok";
+char login_server_db[32] = "ragnarok";
+
+char item_db_db[32] = "item_db";
+char mob_db_db[32] = "mob_db";
+char login_db[32] = "login";
+char login_db_level[32] = "level";
+char login_db_account_id[32] = "account_id";
+
+char log_db[32] = "log";
+char log_db_ip[16] = "127.0.0.1";
+char log_db_id[32] = "ragnarok";
+char log_db_pw[32] = "ragnarok";
+int log_db_port = 3306;
+
+char gm_db[32] = "login";
+char gm_db_level[32] = "level";
+char gm_db_account_id[32] = "account_id";
+
+int lowest_gm_level = 1;
+int read_gm_interval = 600000;
+
+char char_db[32] = "char";
+
+static int online_timer(int,unsigned int,int,int);
+
+int CHECK_INTERVAL = 3600000; // [Valaris]
+int check_online_timer=0; // [Valaris]
+
+#endif /* not TXT_ONLY */
+// 極力 staticでローカルに収める
+static struct dbt * id_db=NULL;
+static struct dbt * map_db=NULL;
+static struct dbt * nick_db=NULL;
+static struct dbt * charid_db=NULL;
+
+static int users=0;
+static struct block_list *object[MAX_FLOORITEM];
+static int first_free_object_id=0,last_object_id=0;
+
+#define block_free_max 1048576
+static void *block_free[block_free_max];
+static int block_free_count = 0, block_free_lock = 0;
+
+#define BL_LIST_MAX 1048576
+static struct block_list *bl_list[BL_LIST_MAX];
+static int bl_list_count = 0;
+
+struct map_data map[MAX_MAP_PER_SERVER];
+int map_num = 0;
+
+int map_port=0;
+
+int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
+int agit_flag = 0;
+int night_flag = 0; // 0=day, 1=night [Yor]
+
+//Added for Mugendai's I'm Alive mod
+int imalive_on=0;
+int imalive_time=60;
+//Added by Mugendai for GUI
+int flush_on=1;
+int flush_time=100;
+
+struct charid2nick {
+ char nick[24];
+ int req_id;
+};
+
+char motd_txt[256] = "conf/motd.txt";
+char help_txt[256] = "conf/help.txt";
+
+char wisp_server_name[24] = "Server"; // can be modified in char-server configuration file
+
+int console = 0;
+/*==========================================
+ * 全map鯖総計での接続数設定
+ * (char鯖から送られてくる)
+ *------------------------------------------
+ */
+void map_setusers(int n) {
+ users = n;
+}
+
+/*==========================================
+ * 全map鯖総計での接続数取得 (/wへの応答用)
+ *------------------------------------------
+ */
+int map_getusers(void) {
+ return users;
+}
+
+//
+// block削除の安全性確保処理
+//
+
+/*==========================================
+ * blockをfreeするときfreeの変わりに呼ぶ
+ * ロックされているときはバッファにためる
+ *------------------------------------------
+ */
+int map_freeblock( void *bl )
+{
+ if(block_free_lock==0){
+ free(bl);
+ bl = NULL;
+ }
+ else{
+ if( block_free_count>=block_free_max ) {
+ if(battle_config.error_log)
+ printf("map_freeblock: *WARNING* too many free block! %d %d\n",
+ block_free_count,block_free_lock);
+ }
+ else
+ block_free[block_free_count++]=bl;
+ }
+ return block_free_lock;
+}
+/*==========================================
+ * blockのfreeを一時的に禁止する
+ *------------------------------------------
+ */
+int map_freeblock_lock(void) {
+ return ++block_free_lock;
+}
+
+/*==========================================
+ * blockのfreeのロックを解除する
+ * このとき、ロックが完全になくなると
+ * バッファにたまっていたblockを全部削除
+ *------------------------------------------
+ */
+int map_freeblock_unlock(void) {
+ if ((--block_free_lock) == 0) {
+ int i;
+// if(block_free_count>0) {
+// if(battle_config.error_log)
+// printf("map_freeblock_unlock: free %d object\n",block_free_count);
+// }
+ for(i=0;i<block_free_count;i++){
+ free(block_free[i]);
+ block_free[i] = NULL;
+ }
+ block_free_count=0;
+ }else if(block_free_lock<0){
+ if(battle_config.error_log)
+ printf("map_freeblock_unlock: lock count < 0 !\n");
+ }
+ return block_free_lock;
+}
+
+
+//
+// block化処理
+//
+/*==========================================
+ * map[]のblock_listから繋がっている場合に
+ * bl->prevにbl_headのアドレスを入れておく
+ *------------------------------------------
+ */
+static struct block_list bl_head;
+
+/*==========================================
+ * map[]のblock_listに追加
+ * mobは数が多いので別リスト
+ *
+ * 既にlink済みかの確認が無い。危険かも
+ *------------------------------------------
+ */
+int map_addblock(struct block_list *bl)
+{
+ int m,x,y;
+
+ nullpo_retr(0, bl);
+
+ if(bl->prev != NULL){
+ if(battle_config.error_log)
+ printf("map_addblock error : bl->prev!=NULL\n");
+ return 0;
+ }
+
+ m=bl->m;
+ x=bl->x;
+ y=bl->y;
+ if(m<0 || m>=map_num ||
+ x<0 || x>=map[m].xs ||
+ y<0 || y>=map[m].ys)
+ return 1;
+
+ if(bl->type==BL_MOB){
+ bl->next = map[m].block_mob[x/BLOCK_SIZE+(y/BLOCK_SIZE)*map[m].bxs];
+ bl->prev = &bl_head;
+ if(bl->next) bl->next->prev = bl;
+ map[m].block_mob[x/BLOCK_SIZE+(y/BLOCK_SIZE)*map[m].bxs] = bl;
+ map[m].block_mob_count[x/BLOCK_SIZE+(y/BLOCK_SIZE)*map[m].bxs]++;
+ } else {
+ bl->next = map[m].block[x/BLOCK_SIZE+(y/BLOCK_SIZE)*map[m].bxs];
+ bl->prev = &bl_head;
+ if(bl->next) bl->next->prev = bl;
+ map[m].block[x/BLOCK_SIZE+(y/BLOCK_SIZE)*map[m].bxs] = bl;
+ map[m].block_count[x/BLOCK_SIZE+(y/BLOCK_SIZE)*map[m].bxs]++;
+ if(bl->type==BL_PC)
+ map[m].users++;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * map[]のblock_listから外す
+ * prevがNULLの場合listに繋がってない
+ *------------------------------------------
+ */
+int map_delblock(struct block_list *bl)
+{
+ int b;
+ nullpo_retr(0, bl);
+
+ // 既にblocklistから抜けている
+ if(bl->prev==NULL){
+ if(bl->next!=NULL){
+ // prevがNULLでnextがNULLでないのは有ってはならない
+ if(battle_config.error_log)
+ printf("map_delblock error : bl->next!=NULL\n");
+ }
+ return 0;
+ }
+
+ b = bl->x/BLOCK_SIZE+(bl->y/BLOCK_SIZE)*map[bl->m].bxs;
+
+ if(bl->type==BL_PC)
+ map[bl->m].users--;
+ if(bl->next) bl->next->prev = bl->prev;
+ if(bl->prev==&bl_head){
+ // リストの頭なので、map[]のblock_listを更新する
+ if(bl->type==BL_MOB){
+ map[bl->m].block_mob[b] = bl->next;
+ if((map[bl->m].block_mob_count[b]--) < 0)
+ map[bl->m].block_mob_count[b] = 0;
+ } else {
+ map[bl->m].block[b] = bl->next;
+ if((map[bl->m].block_count[b]--) < 0)
+ map[bl->m].block_count[b] = 0;
+ }
+ } else {
+ bl->prev->next = bl->next;
+ }
+ bl->next = NULL;
+ bl->prev = NULL;
+
+ return 0;
+}
+
+/*==========================================
+ * 周囲のPC人数を数える (現在未使用)
+ *------------------------------------------
+ */
+int map_countnearpc(int m, int x, int y) {
+ int bx,by,c=0;
+ struct block_list *bl=NULL;
+
+ if(map[m].users==0)
+ return 0;
+ for(by=y/BLOCK_SIZE-AREA_SIZE/BLOCK_SIZE-1;by<=y/BLOCK_SIZE+AREA_SIZE/BLOCK_SIZE+1;by++){
+ if(by<0 || by>=map[m].bys)
+ continue;
+ for(bx=x/BLOCK_SIZE-AREA_SIZE/BLOCK_SIZE-1;bx<=x/BLOCK_SIZE+AREA_SIZE/BLOCK_SIZE+1;bx++){
+ if(bx<0 || bx>=map[m].bxs)
+ continue;
+ bl = map[m].block[bx+by*map[m].bxs];
+ for(;bl;bl=bl->next){
+ if(bl->type==BL_PC)
+ c++;
+ }
+ }
+ }
+ return c;
+}
+
+/*==========================================
+ * セル上のPCとMOBの数を数える (グランドクロス用)
+ *------------------------------------------
+ */
+int map_count_oncell(int m, int x, int y) {
+ int bx,by;
+ struct block_list *bl=NULL;
+ int i,c;
+ int count = 0;
+
+ if (x < 0 || y < 0 || (x >= map[m].xs) || (y >= map[m].ys))
+ return 1;
+ bx = x/BLOCK_SIZE;
+ by = y/BLOCK_SIZE;
+
+ bl = map[m].block[bx+by*map[m].bxs];
+ c = map[m].block_count[bx+by*map[m].bxs];
+ for(i=0;i<c && bl;i++,bl=bl->next){
+ if(bl->x == x && bl->y == y && bl->type == BL_PC) count++;
+ }
+ bl = map[m].block_mob[bx+by*map[m].bxs];
+ c = map[m].block_mob_count[bx+by*map[m].bxs];
+ for(i=0;i<c && bl;i++,bl=bl->next){
+ if(bl->x == x && bl->y == y) count++;
+ }
+ if(!count) count = 1;
+ return count;
+}
+
+
+/*==========================================
+ * map m (x0,y0)-(x1,y1)内の全objに対して
+ * funcを呼ぶ
+ * type!=0 ならその種類のみ
+ *------------------------------------------
+ */
+void map_foreachinarea(int (*func)(struct block_list*,va_list),int m,int x0,int y0,int x1,int y1,int type,...) {
+ int bx,by;
+ struct block_list *bl=NULL;
+ va_list ap=NULL;
+ int blockcount=bl_list_count,i,c;
+
+ if(m < 0)
+ return;
+ va_start(ap,type);
+ if (x0 < 0) x0 = 0;
+ if (y0 < 0) y0 = 0;
+ if (x1 >= map[m].xs) x1 = map[m].xs-1;
+ if (y1 >= map[m].ys) y1 = map[m].ys-1;
+ if (type == 0 || type != BL_MOB)
+ for (by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++) {
+ for(bx=x0/BLOCK_SIZE;bx<=x1/BLOCK_SIZE;bx++){
+ bl = map[m].block[bx+by*map[m].bxs];
+ c = map[m].block_count[bx+by*map[m].bxs];
+ for(i=0;i<c && bl;i++,bl=bl->next){
+ if(bl && type && bl->type!=type)
+ continue;
+ if(bl && bl->x>=x0 && bl->x<=x1 && bl->y>=y0 && bl->y<=y1 && bl_list_count<BL_LIST_MAX)
+ bl_list[bl_list_count++]=bl;
+ }
+ }
+ }
+ if(type==0 || type==BL_MOB)
+ for(by=y0/BLOCK_SIZE;by<=y1/BLOCK_SIZE;by++){
+ for(bx=x0/BLOCK_SIZE;bx<=x1/BLOCK_SIZE;bx++){
+ bl = map[m].block_mob[bx+by*map[m].bxs];
+ c = map[m].block_mob_count[bx+by*map[m].bxs];
+ for(i=0;i<c && bl;i++,bl=bl->next){
+ if(bl && bl->x>=x0 && bl->x<=x1 && bl->y>=y0 && bl->y<=y1 && bl_list_count<BL_LIST_MAX)
+ bl_list[bl_list_count++]=bl;
+ }
+ }
+ }
+
+ if(bl_list_count>=BL_LIST_MAX) {
+ if(battle_config.error_log)
+ printf("map_foreachinarea: *WARNING* block count too many!\n");
+ }
+
+ map_freeblock_lock(); // メモリからの解放を禁止する
+
+ for(i=blockcount;i<bl_list_count;i++)
+ if(bl_list[i]->prev) // 有効かどうかチェック
+ func(bl_list[i],ap);
+
+ map_freeblock_unlock(); // 解放を許可する
+
+ va_end(ap);
+ bl_list_count = blockcount;
+}
+
+/*==========================================
+ * 矩形(x0,y0)-(x1,y1)が(dx,dy)移動した時の
+ * 領域外になる領域(矩形かL字形)内のobjに
+ * 対してfuncを呼ぶ
+ *
+ * dx,dyは-1,0,1のみとする(どんな値でもいいっぽい?)
+ *------------------------------------------
+ */
+void map_foreachinmovearea(int (*func)(struct block_list*,va_list),int m,int x0,int y0,int x1,int y1,int dx,int dy,int type,...) {
+ int bx,by;
+ struct block_list *bl=NULL;
+ va_list ap=NULL;
+ int blockcount=bl_list_count,i,c;
+
+ va_start(ap,type);
+ if(dx==0 || dy==0){
+ // 矩形領域の場合
+ if(dx==0){
+ if(dy<0){
+ y0=y1+dy+1;
+ } else {
+ y1=y0+dy-1;
+ }
+ } else if(dy==0){
+ if(dx<0){
+ x0=x1+dx+1;
+ } else {
+ x1=x0+dx-1;
+ }
+ }
+ if(x0<0) x0=0;
+ if(y0<0) y0=0;
+ if(x1>=map[m].xs) x1=map[m].xs-1;
+ if(y1>=map[m].ys) y1=map[m].ys-1;
+ for(by=y0/BLOCK_SIZE;by<=y1/BLOCK_SIZE;by++){
+ for(bx=x0/BLOCK_SIZE;bx<=x1/BLOCK_SIZE;bx++){
+ bl = map[m].block[bx+by*map[m].bxs];
+ c = map[m].block_count[bx+by*map[m].bxs];
+ for(i=0;i<c && bl;i++,bl=bl->next){
+ if(bl && type && bl->type!=type)
+ continue;
+ if(bl && bl->x>=x0 && bl->x<=x1 && bl->y>=y0 && bl->y<=y1 && bl_list_count<BL_LIST_MAX)
+ bl_list[bl_list_count++]=bl;
+ }
+ bl = map[m].block_mob[bx+by*map[m].bxs];
+ c = map[m].block_mob_count[bx+by*map[m].bxs];
+ for(i=0;i<c && bl;i++,bl=bl->next){
+ if(bl && type && bl->type!=type)
+ continue;
+ if(bl && bl->x>=x0 && bl->x<=x1 && bl->y>=y0 && bl->y<=y1 && bl_list_count<BL_LIST_MAX)
+ bl_list[bl_list_count++]=bl;
+ }
+ }
+ }
+ }else{
+ // L字領域の場合
+
+ if(x0<0) x0=0;
+ if(y0<0) y0=0;
+ if(x1>=map[m].xs) x1=map[m].xs-1;
+ if(y1>=map[m].ys) y1=map[m].ys-1;
+ for(by=y0/BLOCK_SIZE;by<=y1/BLOCK_SIZE;by++){
+ for(bx=x0/BLOCK_SIZE;bx<=x1/BLOCK_SIZE;bx++){
+ bl = map[m].block[bx+by*map[m].bxs];
+ c = map[m].block_count[bx+by*map[m].bxs];
+ for(i=0;i<c && bl;i++,bl=bl->next){
+ if(bl && type && bl->type!=type)
+ continue;
+ if((bl) && !(bl->x>=x0 && bl->x<=x1 && bl->y>=y0 && bl->y<=y1))
+ continue;
+ if((bl) && ((dx>0 && bl->x<x0+dx) || (dx<0 && bl->x>x1+dx) ||
+ (dy>0 && bl->y<y0+dy) || (dy<0 && bl->y>y1+dy)) &&
+ bl_list_count<BL_LIST_MAX)
+ bl_list[bl_list_count++]=bl;
+ }
+ bl = map[m].block_mob[bx+by*map[m].bxs];
+ c = map[m].block_mob_count[bx+by*map[m].bxs];
+ for(i=0;i<c && bl;i++,bl=bl->next){
+ if(bl && type && bl->type!=type)
+ continue;
+ if((bl) && !(bl->x>=x0 && bl->x<=x1 && bl->y>=y0 && bl->y<=y1))
+ continue;
+ if((bl) && ((dx>0 && bl->x<x0+dx) || (dx<0 && bl->x>x1+dx) ||
+ (dy>0 && bl->y<y0+dy) || (dy<0 && bl->y>y1+dy)) &&
+ bl_list_count<BL_LIST_MAX)
+ bl_list[bl_list_count++]=bl;
+ }
+ }
+ }
+
+ }
+
+ if(bl_list_count>=BL_LIST_MAX) {
+ if(battle_config.error_log)
+ printf("map_foreachinarea: *WARNING* block count too many!\n");
+ }
+
+ map_freeblock_lock(); // メモリからの解放を禁止する
+
+ for(i=blockcount;i<bl_list_count;i++)
+ if(bl_list[i]->prev) // 有効かどうかチェック
+ func(bl_list[i],ap);
+
+ map_freeblock_unlock(); // 解放を許可する
+
+ va_end(ap);
+ bl_list_count = blockcount;
+}
+
+// -- moonsoul (added map_foreachincell which is a rework of map_foreachinarea but
+// which only checks the exact single x/y passed to it rather than an
+// area radius - may be more useful in some instances)
+//
+void map_foreachincell(int (*func)(struct block_list*,va_list),int m,int x,int y,int type,...) {
+ int bx,by;
+ struct block_list *bl=NULL;
+ va_list ap=NULL;
+ int blockcount=bl_list_count,i,c;
+
+ va_start(ap,type);
+
+ by=y/BLOCK_SIZE;
+ bx=x/BLOCK_SIZE;
+
+ if(type==0 || type!=BL_MOB)
+ {
+ bl = map[m].block[bx+by*map[m].bxs];
+ c = map[m].block_count[bx+by*map[m].bxs];
+ for(i=0;i<c && bl;i++,bl=bl->next)
+ {
+ if(type && bl && bl->type!=type)
+ continue;
+ if(bl && bl->x==x && bl->y==y && bl_list_count<BL_LIST_MAX)
+ bl_list[bl_list_count++]=bl;
+ }
+ }
+
+ if(type==0 || type==BL_MOB)
+ {
+ bl = map[m].block_mob[bx+by*map[m].bxs];
+ c = map[m].block_mob_count[bx+by*map[m].bxs];
+ for(i=0;i<c && bl;i++,bl=bl->next)
+ {
+ if(bl && bl->x==x && bl->y==y && bl_list_count<BL_LIST_MAX)
+ bl_list[bl_list_count++]=bl;
+ }
+ }
+
+ if(bl_list_count>=BL_LIST_MAX) {
+ if(battle_config.error_log)
+ printf("map_foreachincell: *WARNING* block count too many!\n");
+ }
+
+ map_freeblock_lock(); // メモリからの解放を禁止する
+
+ for(i=blockcount;i<bl_list_count;i++)
+ if(bl_list[i]->prev) // 有効かどうかチェック
+ func(bl_list[i],ap);
+
+ map_freeblock_unlock(); // 解放を許可する
+
+ va_end(ap);
+ bl_list_count = blockcount;
+}
+
+/*==========================================
+ * 床アイテムやエフェクト用の一時obj割り当て
+ * object[]への保存とid_db登録まで
+ *
+ * bl->idもこの中で設定して問題無い?
+ *------------------------------------------
+ */
+int map_addobject(struct block_list *bl) {
+ int i;
+ if( bl == NULL ){
+ printf("map_addobject nullpo?\n");
+ return 0;
+ }
+ if(first_free_object_id<2 || first_free_object_id>=MAX_FLOORITEM)
+ first_free_object_id=2;
+ for(i=first_free_object_id;i<MAX_FLOORITEM;i++)
+ if(object[i]==NULL)
+ break;
+ if(i>=MAX_FLOORITEM){
+ if(battle_config.error_log)
+ printf("no free object id\n");
+ return 0;
+ }
+ first_free_object_id=i;
+ if(last_object_id<i)
+ last_object_id=i;
+ object[i]=bl;
+ numdb_insert(id_db,i,bl);
+ return i;
+}
+
+/*==========================================
+ * 一時objectの解放
+ * map_delobjectのfreeしないバージョン
+ *------------------------------------------
+ */
+int map_delobjectnofree(int id) {
+ if(object[id]==NULL)
+ return 0;
+
+ map_delblock(object[id]);
+ numdb_erase(id_db,id);
+// map_freeblock(object[id]);
+ object[id]=NULL;
+
+ if(first_free_object_id>id)
+ first_free_object_id=id;
+
+ while(last_object_id>2 && object[last_object_id]==NULL)
+ last_object_id--;
+
+ return 0;
+}
+
+/*==========================================
+ * 一時objectの解放
+ * block_listからの削除、id_dbからの削除
+ * object dataのfree、object[]へのNULL代入
+ *
+ * addとの対称性が無いのが気になる
+ *------------------------------------------
+ */
+int map_delobject(int id) {
+ struct block_list *obj = object[id];
+
+ if(obj==NULL)
+ return 0;
+
+ map_delobjectnofree(id);
+ map_freeblock(obj);
+
+ return 0;
+}
+
+/*==========================================
+ * 全一時obj相手にfuncを呼ぶ
+ *
+ *------------------------------------------
+ */
+void map_foreachobject(int (*func)(struct block_list*,va_list),int type,...) {
+ int i;
+ int blockcount=bl_list_count;
+ va_list ap=NULL;
+
+ va_start(ap,type);
+
+ for(i=2;i<=last_object_id;i++){
+ if(object[i]){
+ if(type && object[i]->type!=type)
+ continue;
+ if(bl_list_count>=BL_LIST_MAX) {
+ if(battle_config.error_log)
+ printf("map_foreachobject: too many block !\n");
+ }
+ else
+ bl_list[bl_list_count++]=object[i];
+ }
+ }
+
+ map_freeblock_lock();
+
+ for(i=blockcount;i<bl_list_count;i++)
+ if( bl_list[i]->prev || bl_list[i]->next )
+ func(bl_list[i],ap);
+
+ map_freeblock_unlock();
+
+ va_end(ap);
+ bl_list_count = blockcount;
+}
+
+/*==========================================
+ * 床アイテムを消す
+ *
+ * data==0の時はtimerで消えた時
+ * data!=0の時は拾う等で消えた時として動作
+ *
+ * 後者は、map_clearflooritem(id)へ
+ * map.h内で#defineしてある
+ *------------------------------------------
+ */
+int map_clearflooritem_timer(int tid,unsigned int tick,int id,int data) {
+ struct flooritem_data *fitem=NULL;
+
+ fitem = (struct flooritem_data *)object[id];
+ if(fitem==NULL || fitem->bl.type!=BL_ITEM || (!data && fitem->cleartimer != tid)){
+ if(battle_config.error_log)
+ printf("map_clearflooritem_timer : error\n");
+ return 1;
+ }
+ if(data)
+ delete_timer(fitem->cleartimer,map_clearflooritem_timer);
+ else if(fitem->item_data.card[0] == (short)0xff00)
+ intif_delete_petdata(*((long *)(&fitem->item_data.card[1])));
+ clif_clearflooritem(fitem,0);
+ map_delobject(fitem->bl.id);
+
+ return 0;
+}
+
+/*==========================================
+ * (m,x,y)の周囲rangeマス内の空き(=侵入可能)cellの
+ * 内から適当なマス目の座標をx+(y<<16)で返す
+ *
+ * 現状range=1でアイテムドロップ用途のみ
+ *------------------------------------------
+ */
+int map_searchrandfreecell(int m,int x,int y,int range) {
+ int free_cell,i,j,c;
+
+ for(free_cell=0,i=-range;i<=range;i++){
+ if(i+y<0 || i+y>=map[m].ys)
+ continue;
+ for(j=-range;j<=range;j++){
+ if(j+x<0 || j+x>=map[m].xs)
+ continue;
+ if((c=read_gat(m,j+x,i+y))==1 || c==5)
+ continue;
+ free_cell++;
+ }
+ }
+ if(free_cell==0)
+ return -1;
+ free_cell=rand()%free_cell;
+ for(i=-range;i<=range;i++){
+ if(i+y<0 || i+y>=map[m].ys)
+ continue;
+ for(j=-range;j<=range;j++){
+ if(j+x<0 || j+x>=map[m].xs)
+ continue;
+ if((c=read_gat(m,j+x,i+y))==1 || c==5)
+ continue;
+ if(free_cell==0){
+ x+=j;
+ y+=i;
+ i=range+1;
+ break;
+ }
+ free_cell--;
+ }
+ }
+
+ return x+(y<<16);
+}
+
+/*==========================================
+ * (m,x,y)を中心に3x3以内に床アイテム設置
+ *
+ * item_dataはamount以外をcopyする
+ *------------------------------------------
+ */
+int map_addflooritem(struct item *item_data,int amount,int m,int x,int y,struct map_session_data *first_sd,
+ struct map_session_data *second_sd,struct map_session_data *third_sd,int type) {
+ int xy,r;
+ unsigned int tick;
+ struct flooritem_data *fitem=NULL;
+
+ nullpo_retr(0, item_data);
+
+ if((xy=map_searchrandfreecell(m,x,y,1))<0)
+ return 0;
+ r=rand();
+
+ fitem = (struct flooritem_data *)aCalloc(1,sizeof(*fitem));
+ fitem->bl.type=BL_ITEM;
+ fitem->bl.prev = fitem->bl.next = NULL;
+ fitem->bl.m=m;
+ fitem->bl.x=xy&0xffff;
+ fitem->bl.y=(xy>>16)&0xffff;
+ fitem->first_get_id = 0;
+ fitem->first_get_tick = 0;
+ fitem->second_get_id = 0;
+ fitem->second_get_tick = 0;
+ fitem->third_get_id = 0;
+ fitem->third_get_tick = 0;
+
+ fitem->bl.id = map_addobject(&fitem->bl);
+ if(fitem->bl.id==0){
+ free(fitem);
+ return 0;
+ }
+
+ tick = gettick();
+ if(first_sd) {
+ fitem->first_get_id = first_sd->bl.id;
+ if(type)
+ fitem->first_get_tick = tick + battle_config.mvp_item_first_get_time;
+ else
+ fitem->first_get_tick = tick + battle_config.item_first_get_time;
+ }
+ if(second_sd) {
+ fitem->second_get_id = second_sd->bl.id;
+ if(type)
+ fitem->second_get_tick = tick + battle_config.mvp_item_first_get_time + battle_config.mvp_item_second_get_time;
+ else
+ fitem->second_get_tick = tick + battle_config.item_first_get_time + battle_config.item_second_get_time;
+ }
+ if(third_sd) {
+ fitem->third_get_id = third_sd->bl.id;
+ if(type)
+ fitem->third_get_tick = tick + battle_config.mvp_item_first_get_time + battle_config.mvp_item_second_get_time + battle_config.mvp_item_third_get_time;
+ else
+ fitem->third_get_tick = tick + battle_config.item_first_get_time + battle_config.item_second_get_time + battle_config.item_third_get_time;
+ }
+
+ memcpy(&fitem->item_data,item_data,sizeof(*item_data));
+ fitem->item_data.amount=amount;
+ fitem->subx=(r&3)*3+3;
+ fitem->suby=((r>>2)&3)*3+3;
+ fitem->cleartimer=add_timer(gettick()+battle_config.flooritem_lifetime,map_clearflooritem_timer,fitem->bl.id,0);
+
+ map_addblock(&fitem->bl);
+ clif_dropflooritem(fitem);
+
+ return fitem->bl.id;
+}
+
+/*==========================================
+ * charid_dbへ追加(返信待ちがあれば返信)
+ *------------------------------------------
+ */
+void map_addchariddb(int charid, char *name) {
+ struct charid2nick *p=NULL;
+ int req=0;
+
+ p=numdb_search(charid_db,charid);
+ if(p==NULL){ // データベースにない
+ p = (struct charid2nick *)aCalloc(1,sizeof(struct charid2nick));
+ p->req_id=0;
+ }else
+ numdb_erase(charid_db,charid);
+
+ req=p->req_id;
+ memcpy(p->nick,name,24);
+ p->req_id=0;
+ numdb_insert(charid_db,charid,p);
+ if(req){ // 返信待ちがあれば返信
+ struct map_session_data *sd = map_id2sd(req);
+ if(sd!=NULL)
+ clif_solved_charname(sd,charid);
+ }
+}
+
+/*==========================================
+ * charid_dbへ追加(返信要求のみ)
+ *------------------------------------------
+ */
+int map_reqchariddb(struct map_session_data * sd,int charid) {
+ struct charid2nick *p=NULL;
+
+ nullpo_retr(0, sd);
+
+ p=numdb_search(charid_db,charid);
+ if(p!=NULL) // データベースにすでにある
+ return 0;
+ p = (struct charid2nick *)aCalloc(1,sizeof(struct charid2nick));
+ p->req_id=sd->bl.id;
+ numdb_insert(charid_db,charid,p);
+ return 0;
+}
+
+/*==========================================
+ * id_dbへblを追加
+ *------------------------------------------
+ */
+void map_addiddb(struct block_list *bl) {
+ nullpo_retv(bl);
+
+ numdb_insert(id_db,bl->id,bl);
+}
+
+/*==========================================
+ * id_dbからblを削除
+ *------------------------------------------
+ */
+void map_deliddb(struct block_list *bl) {
+ nullpo_retv(bl);
+
+ numdb_erase(id_db,bl->id);
+}
+
+/*==========================================
+ * nick_dbへsdを追加
+ *------------------------------------------
+ */
+void map_addnickdb(struct map_session_data *sd) {
+ nullpo_retv(sd);
+
+ strdb_insert(nick_db,sd->status.name,sd);
+}
+
+/*==========================================
+ * PCのquit処理 map.c内分
+ *
+ * quit処理の主体が違うような気もしてきた
+ *------------------------------------------
+ */
+int map_quit(struct map_session_data *sd) {
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if(sd->chatID) // チャットから出る
+ chat_leavechat(sd);
+
+ if(sd->trade_partner) // 取引を中断する
+ trade_tradecancel(sd);
+
+ if(sd->party_invite>0) // パーティ勧誘を拒否する
+ party_reply_invite(sd,sd->party_invite_account,0);
+
+ if(sd->guild_invite>0) // ギルド勧誘を拒否する
+ guild_reply_invite(sd,sd->guild_invite,0);
+ if(sd->guild_alliance>0) // ギルド同盟勧誘を拒否する
+ guild_reply_reqalliance(sd,sd->guild_alliance_account,0);
+
+ party_send_logout(sd); // パーティのログアウトメッセージ送信
+
+ guild_send_memberinfoshort(sd,0); // ギルドのログアウトメッセージ送信
+
+ pc_cleareventtimer(sd); // イベントタイマを破棄する
+
+ if(sd->state.storage_flag)
+ storage_guild_storage_quit(sd,0);
+ else
+ storage_storage_quit(sd); // 倉庫を開いてるなら保存する
+
+ skill_castcancel(&sd->bl,0); // 詠唱を中断する
+ skill_stop_dancing(&sd->bl,1);// ダンス/演奏中断
+
+ if(sd->sc_data && sd->sc_data[SC_BERSERK].timer!=-1) //バーサーク中の終了はHPを100に
+ sd->status.hp = 100;
+
+ skill_status_change_clear(&sd->bl,1); // ステータス異常を解除する
+ skill_clear_unitgroup(&sd->bl); // スキルユニットグループの削除
+ skill_cleartimerskill(&sd->bl);
+ pc_stop_walking(sd,0);
+ pc_stopattack(sd);
+ pc_delinvincibletimer(sd);
+ pc_delspiritball(sd,sd->spiritball,1);
+ skill_gangsterparadise(sd,0);
+
+ pc_calcstatus(sd,4);
+
+ clif_clearchar_area(&sd->bl,2);
+
+ if(sd->status.pet_id && sd->pd) {
+ pet_lootitem_drop(sd->pd,sd);
+ pet_remove_map(sd);
+ if(sd->pet.intimate <= 0) {
+ intif_delete_petdata(sd->status.pet_id);
+ sd->status.pet_id = 0;
+ sd->pd = NULL;
+ sd->petDB = NULL;
+ }
+ else
+ intif_save_petdata(sd->status.account_id,&sd->pet);
+ }
+
+ if(pc_isdead(sd))
+ pc_setrestartvalue(sd,2);
+ pc_makesavestatus(sd);
+ //クローンスキルで覚えたスキルは消す
+ for(i=0;i<MAX_SKILL;i++){
+ if(sd->status.skill[i].flag == 13){
+ sd->status.skill[i].id=0;
+ sd->status.skill[i].lv=0;
+ sd->status.skill[i].flag=0;
+ }
+ }
+ chrif_save(sd);
+ storage_storage_save(sd);
+
+ if( sd->npc_stackbuf && sd->npc_stackbuf != NULL)
+ free( sd->npc_stackbuf );
+
+ map_delblock(&sd->bl);
+
+#ifndef TXT_ONLY
+ chrif_char_offline(sd);
+#endif
+
+ numdb_erase(id_db,sd->bl.id);
+ strdb_erase(nick_db,sd->status.name);
+ numdb_erase(charid_db,sd->status.char_id);
+
+ return 0;
+}
+
+/*==========================================
+ * id番号のPCを探す。居なければNULL
+ *------------------------------------------
+ */
+struct map_session_data * map_id2sd(int id) {
+// remove search from db, because:
+// 1 - all players, npc, items and mob are in this db (to search, it's not speed, and search in session is more sure)
+// 2 - DB seems not always correct. Sometimes, when a player disconnects, its id (account value) is not removed and structure
+// point to a memory area that is not more a session_data and value are incorrect (or out of available memory) -> crash
+// replaced by searching in all session.
+// by searching in session, we are sure that fd, session, and account exist.
+/*
+ struct block_list *bl;
+
+ bl=numdb_search(id_db,id);
+ if(bl && bl->type==BL_PC)
+ return (struct map_session_data*)bl;
+ return NULL;
+*/
+ int i;
+ struct map_session_data *sd=NULL;
+
+ for(i = 0; i < fd_max; i++)
+ if (session[i] && (sd = session[i]->session_data) && sd->bl.id == id)
+ return sd;
+
+ return NULL;
+}
+
+/*==========================================
+ * char_id番号の名前を探す
+ *------------------------------------------
+ */
+char * map_charid2nick(int id) {
+ struct charid2nick *p=numdb_search(charid_db,id);
+
+ if(p==NULL)
+ return NULL;
+ if(p->req_id!=0)
+ return NULL;
+ return p->nick;
+}
+
+
+/*==========================================
+ * Search session data from a nick name
+ * (without sensitive case if necessary)
+ * return map_session_data pointer or NULL
+ *------------------------------------------
+ */
+struct map_session_data * map_nick2sd(char *nick) {
+ int i, quantity=0, nicklen;
+ struct map_session_data *sd = NULL;
+ struct map_session_data *pl_sd = NULL;
+
+ if (nick == NULL)
+ return NULL;
+
+ nicklen = strlen(nick);
+
+ for (i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth)
+ // Without case sensitive check (increase the number of similar character names found)
+ if (strnicmp(pl_sd->status.name, nick, nicklen) == 0) {
+ // Strict comparison (if found, we finish the function immediatly with correct value)
+ if (strcmp(pl_sd->status.name, nick) == 0)
+ return pl_sd;
+ quantity++;
+ sd = pl_sd;
+ }
+ }
+ // Here, the exact character name is not found
+ // We return the found index of a similar account ONLY if there is 1 similar character
+ if (quantity == 1)
+ return sd;
+
+ // Exact character name is not found and 0 or more than 1 similar characters have been found ==> we say not found
+ return NULL;
+}
+
+/*==========================================
+ * id番号の物を探す
+ * 一時objectの場合は配列を引くのみ
+ *------------------------------------------
+ */
+struct block_list * map_id2bl(int id)
+{
+ struct block_list *bl=NULL;
+ if(id<sizeof(object)/sizeof(object[0]))
+ bl = object[id];
+ else
+ bl = numdb_search(id_db,id);
+
+ return bl;
+}
+
+/*==========================================
+ * id_db内の全てにfuncを実行
+ *------------------------------------------
+ */
+int map_foreachiddb(int (*func)(void*,void*,va_list),...) {
+ va_list ap=NULL;
+
+ va_start(ap,func);
+ numdb_foreach(id_db,func,ap);
+ va_end(ap);
+ return 0;
+}
+
+/*==========================================
+ * map.npcへ追加 (warp等の領域持ちのみ)
+ *------------------------------------------
+ */
+int map_addnpc(int m,struct npc_data *nd) {
+ int i;
+ if(m<0 || m>=map_num)
+ return -1;
+ for(i=0;i<map[m].npc_num && i<MAX_NPC_PER_MAP;i++)
+ if(map[m].npc[i]==NULL)
+ break;
+ if(i==MAX_NPC_PER_MAP){
+ if(battle_config.error_log)
+ printf("too many NPCs in one map %s\n",map[m].name);
+ return -1;
+ }
+ if(i==map[m].npc_num){
+ map[m].npc_num++;
+ }
+
+ nullpo_retr(0, nd);
+
+ map[m].npc[i]=nd;
+ nd->n = i;
+ numdb_insert(id_db,nd->bl.id,nd);
+
+ return i;
+}
+
+void map_removenpc(void) {
+ int i,m,n=0;
+
+ for(m=0;m<map_num;m++) {
+ for(i=0;i<map[m].npc_num && i<MAX_NPC_PER_MAP;i++) {
+ if(map[m].npc[i]!=NULL) {
+ clif_clearchar_area(&map[m].npc[i]->bl,2);
+ map_delblock(&map[m].npc[i]->bl);
+ numdb_erase(id_db,map[m].npc[i]->bl.id);
+ if(map[m].npc[i]->bl.subtype==SCRIPT) {
+// free(map[m].npc[i]->u.scr.script);
+// free(map[m].npc[i]->u.scr.label_list);
+ }
+ free(map[m].npc[i]);
+ map[m].npc[i] = NULL;
+ n++;
+ }
+ }
+ }
+ printf("%d NPCs removed.\n",n);
+}
+
+/*==========================================
+ * map名からmap番号へ変換
+ *------------------------------------------
+ */
+int map_mapname2mapid(char *name) {
+ struct map_data *md=NULL;
+
+ md=strdb_search(map_db,name);
+ if(md==NULL || md->gat==NULL)
+ return -1;
+ return md->m;
+}
+
+/*==========================================
+ * 他鯖map名からip,port変換
+ *------------------------------------------
+ */
+int map_mapname2ipport(char *name,int *ip,int *port) {
+ struct map_data_other_server *mdos=NULL;
+
+ mdos=strdb_search(map_db,name);
+ if(mdos==NULL || mdos->gat)
+ return -1;
+ *ip=mdos->ip;
+ *port=mdos->port;
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int map_check_dir(int s_dir,int t_dir) {
+ if(s_dir == t_dir)
+ return 0;
+ switch(s_dir) {
+ case 0:
+ if(t_dir == 7 || t_dir == 1 || t_dir == 0)
+ return 0;
+ break;
+ case 1:
+ if(t_dir == 0 || t_dir == 2 || t_dir == 1)
+ return 0;
+ break;
+ case 2:
+ if(t_dir == 1 || t_dir == 3 || t_dir == 2)
+ return 0;
+ break;
+ case 3:
+ if(t_dir == 2 || t_dir == 4 || t_dir == 3)
+ return 0;
+ break;
+ case 4:
+ if(t_dir == 3 || t_dir == 5 || t_dir == 4)
+ return 0;
+ break;
+ case 5:
+ if(t_dir == 4 || t_dir == 6 || t_dir == 5)
+ return 0;
+ break;
+ case 6:
+ if(t_dir == 5 || t_dir == 7 || t_dir == 6)
+ return 0;
+ break;
+ case 7:
+ if(t_dir == 6 || t_dir == 0 || t_dir == 7)
+ return 0;
+ break;
+ }
+ return 1;
+}
+
+/*==========================================
+ * 彼我の方向を計算
+ *------------------------------------------
+ */
+int map_calc_dir( struct block_list *src,int x,int y) {
+ int dir=0;
+ int dx,dy;
+
+ nullpo_retr(0, src);
+
+ dx=x-src->x;
+ dy=y-src->y;
+ if( dx==0 && dy==0 ){ // 彼我の場所一致
+ dir=0; // 上
+ }else if( dx>=0 && dy>=0 ){ // 方向的に右上
+ dir=7; // 右上
+ if( dx*3-1<dy ) dir=0; // 上
+ if( dx>dy*3 ) dir=6; // 右
+ }else if( dx>=0 && dy<=0 ){ // 方向的に右下
+ dir=5; // 右下
+ if( dx*3-1<-dy ) dir=4; // 下
+ if( dx>-dy*3 ) dir=6; // 右
+ }else if( dx<=0 && dy<=0 ){ // 方向的に左下
+ dir=3; // 左下
+ if( dx*3+1>dy ) dir=4; // 下
+ if( dx<dy*3 ) dir=2; // 左
+ }else{ // 方向的に左上
+ dir=1; // 左上
+ if( -dx*3-1<dy ) dir=0; // 上
+ if( -dx>dy*3 ) dir=2; // 左
+ }
+ return dir;
+}
+
+// gat系
+/*==========================================
+ * (m,x,y)の状態を調べる
+ *------------------------------------------
+ */
+int map_getcell(int m,int x,int y) {
+ if(x<0 || x>=map[m].xs-1 || y<0 || y>=map[m].ys-1)
+ return 1;
+ return map[m].gat[x+y*map[m].xs];
+}
+
+/*==========================================
+ * (m,x,y)の状態をtにする
+ *------------------------------------------
+ */
+int map_setcell(int m,int x,int y,int t) {
+ if(x<0 || x>=map[m].xs || y<0 || y>=map[m].ys)
+ return t;
+ return map[m].gat[x+y*map[m].xs]=t;
+}
+
+/*==========================================
+ * 他鯖管理のマップをdbに追加
+ *------------------------------------------
+ */
+int map_setipport(char *name,unsigned long ip,int port) {
+ struct map_data *md=NULL;
+ struct map_data_other_server *mdos=NULL;
+
+ md=strdb_search(map_db,name);
+ if(md==NULL){ // not exist -> add new data
+ mdos=(struct map_data_other_server *)aCalloc(1,sizeof(struct map_data_other_server));
+ memcpy(mdos->name,name,24);
+ mdos->gat = NULL;
+ mdos->ip = ip;
+ mdos->port = port;
+ strdb_insert(map_db,mdos->name,mdos);
+ } else {
+ if(md->gat){ // local -> check data
+ if(ip!=clif_getip() || port!=clif_getport()){
+ printf("from char server : %s -> %08lx:%d\n",name,ip,port);
+ return 1;
+ }
+ } else { // update
+ mdos=(struct map_data_other_server *)md;
+ mdos->ip = ip;
+ mdos->port = port;
+ }
+ }
+ return 0;
+}
+
+// 初期化周り
+/*==========================================
+ * 水場高さ設定
+ *------------------------------------------
+ */
+static struct {
+ char mapname[24];
+ int waterheight;
+} *waterlist=NULL;
+
+#define NO_WATER 1000000
+
+static int map_waterheight(char *mapname) {
+ if(waterlist){
+ int i;
+ for(i=0;waterlist[i].mapname[0] && i < MAX_MAP_PER_SERVER;i++)
+ if(strcmp(waterlist[i].mapname,mapname)==0)
+ return waterlist[i].waterheight;
+ }
+ return NO_WATER;
+}
+
+static void map_readwater(char *watertxt) {
+ char line[1024],w1[1024];
+ FILE *fp=NULL;
+ int n=0;
+
+ fp=fopen(watertxt,"r");
+ if(fp==NULL){
+ printf("file not found: %s\n",watertxt);
+ return;
+ }
+ if(waterlist==NULL)
+ waterlist=aCalloc(MAX_MAP_PER_SERVER,sizeof(*waterlist));
+ while(fgets(line,1020,fp) && n < MAX_MAP_PER_SERVER){
+ int wh,count;
+ if(line[0] == '/' && line[1] == '/')
+ continue;
+ if((count=sscanf(line,"%s%d",w1,&wh)) < 1){
+ continue;
+ }
+ strcpy(waterlist[n].mapname,w1);
+ if(count >= 2)
+ waterlist[n].waterheight = wh;
+ else
+ waterlist[n].waterheight = 3;
+ n++;
+ }
+ fclose(fp);
+}
+
+/*==========================================
+ * マップ1枚読み込み
+ *------------------------------------------
+ */
+static int map_readmap(int m,char *fn, char *alias) {
+ unsigned char *gat="";
+ int s;
+ int x,y,xs,ys;
+ struct gat_1cell {float high[4]; int type;} *p=NULL;
+ int wh;
+ size_t size;
+
+ // read & convert fn
+ gat=grfio_read(fn);
+ if(gat==NULL)
+ return -1;
+
+ printf("\rLoading Maps [%d/%d]: %-50s ",m,map_num,fn);
+ fflush(stdout);
+
+ map[m].m=m;
+ xs=map[m].xs=*(int*)(gat+6);
+ ys=map[m].ys=*(int*)(gat+10);
+ map[m].gat = (unsigned char *)aCalloc(s = map[m].xs * map[m].ys,sizeof(unsigned char));
+ map[m].npc_num=0;
+ map[m].users=0;
+ memset(&map[m].flag,0,sizeof(map[m].flag));
+ if(battle_config.pk_mode) map[m].flag.pvp = 1; // make all maps pvp for pk_mode [Valaris]
+ wh=map_waterheight(map[m].name);
+ for(y=0;y<ys;y++){
+ p=(struct gat_1cell*)(gat+y*xs*20+14);
+ for(x=0;x<xs;x++){
+ if(wh!=NO_WATER && p->type==0){
+ // 水場判定
+ map[m].gat[x+y*xs]=(p->high[0]>wh || p->high[1]>wh || p->high[2]>wh || p->high[3]>wh) ? 3 : 0;
+ } else {
+ map[m].gat[x+y*xs]=p->type;
+ }
+ p++;
+ }
+ }
+ free(gat);
+
+ map[m].bxs=(xs+BLOCK_SIZE-1)/BLOCK_SIZE;
+ map[m].bys=(ys+BLOCK_SIZE-1)/BLOCK_SIZE;
+ size = map[m].bxs * map[m].bys * sizeof(struct block_list*);
+ map[m].block = (struct block_list **)aCalloc(1,size);
+ map[m].block_mob = (struct block_list **)aCalloc(1,size);
+ size = map[m].bxs*map[m].bys*sizeof(int);
+ map[m].block_count = (int *)aCalloc(1,size);
+ map[m].block_mob_count=(int *)aCalloc(1,size);
+ strdb_insert(map_db,map[m].name,&map[m]);
+
+// printf("%s read done\n",fn);
+
+ return 0;
+}
+
+/*==========================================
+ * 全てのmapデータを読み込む
+ *------------------------------------------
+ */
+int map_readallmap(void) {
+ int i,maps_removed=0;
+ char fn[256]="";
+
+ // 先に全部のャbプの存在を確認
+ for(i=0;i<map_num;i++){
+ if(strstr(map[i].name,".gat")==NULL)
+ continue;
+ sprintf(fn,"data\\%s",map[i].name);
+ if(grfio_size(fn) == -1) {
+ map_delmap(map[i].name);
+ maps_removed++;
+ }
+ }
+ for(i=0;i<map_num;i++){
+ if(strstr(map[i].name,".gat")!=NULL) {
+ char *p = strstr(map[i].name, ">"); // [MouseJstr]
+ if (p != NULL) {
+ char alias[64];
+ *p = '\0';
+ strcpy(alias, map[i].name);
+ strcpy(map[i].name, p + 1);
+ sprintf(fn,"data\\%s",map[i].name);
+ if(map_readmap(i,fn, alias) == -1) {
+ map_delmap(map[i].name);
+ maps_removed++;
+ }
+ } else {
+ sprintf(fn,"data\\%s",map[i].name);
+ if(map_readmap(i,fn, NULL) == -1) {
+ map_delmap(map[i].name);
+ maps_removed++;
+ }
+ }
+ }
+ }
+
+ free(waterlist);
+ printf("\rMaps Loaded: %d %60s\n",map_num,"");
+ printf("\rMaps Removed: %d \n",maps_removed);
+ return 0;
+}
+
+/*==========================================
+ * 読み込むmapを追加する
+ *------------------------------------------
+ */
+int map_addmap(char *mapname) {
+ if (strcmpi(mapname,"clear")==0) {
+ map_num=0;
+ return 0;
+ }
+
+ if (map_num >= MAX_MAP_PER_SERVER - 1) {
+ printf("too many map\n");
+ return 1;
+ }
+ memcpy(map[map_num].name, mapname, 24);
+ map_num++;
+ return 0;
+}
+
+/*==========================================
+ * 読み込むmapを削除する
+ *------------------------------------------
+ */
+int map_delmap(char *mapname) {
+ int i;
+
+ if (strcmpi(mapname, "all") == 0) {
+ map_num = 0;
+ return 0;
+ }
+
+ for(i = 0; i < map_num; i++) {
+ if (strcmp(map[i].name, mapname) == 0) {
+ printf("Removing map [ %s ] from maplist\n",map[i].name);
+ memmove(map+i, map+i+1, sizeof(map[0])*(map_num-i-1));
+ map_num--;
+ }
+ }
+ return 0;
+}
+
+static int map_ip_set_ = 0;
+static int char_ip_set_ = 0;
+
+/*==========================================
+ * Console Command Parser [Wizputer]
+ *------------------------------------------
+ */
+int parse_console(char *buf) {
+ char *type,*command,*map, *buf2;
+ int x = 0, y = 0;
+ int m, n;
+ struct map_session_data *sd;
+
+ sd = calloc(sizeof(*sd), 1);
+
+ sd->fd = 0;
+ strcpy( sd->status.name , "console");
+
+ type = (char *)malloc(64);
+ command = (char *)malloc(64);
+ map = (char *)malloc(64);
+ buf2 = (char *)malloc(72);
+
+ memset(type,0,64);
+ memset(command,0,64);
+ memset(map,0,64);
+ memset(buf2,0,72);
+
+ if ( ( n = sscanf(buf, "%[^:]:%[^:]:%99s %d %d[^\n]", type , command , map , &x , &y )) < 5 )
+ if ( ( n = sscanf(buf, "%[^:]:%[^\n]", type , command )) < 2 )
+ n = sscanf(buf,"%[^\n]",type);
+
+ if ( n == 5 ) {
+ if (x <= 0) {
+ x = rand() % 399 + 1;
+ sd->bl.x = x;
+ } else {
+ sd->bl.x = x;
+ }
+
+ if (y <= 0) {
+ y = rand() % 399 + 1;
+ sd->bl.y = y;
+ } else {
+ sd->bl.y = y;
+ }
+
+ m = map_mapname2mapid(map);
+ if ( m >= 0 )
+ sd->bl.m = m;
+ else {
+ printf("Console: Unknown map\n");
+ goto end;
+ }
+ }
+
+ printf("Type of command: %s || Command: %s || Map: %s Coords: %d %d\n",type,command,map,x,y);
+
+ if ( strcmpi("admin",type) == 0 && n == 5 ) {
+ sprintf(buf2,"console: %s",command);
+ if( is_atcommand(sd->fd,sd,buf2,99) == AtCommand_None )
+ printf("Console: not atcommand\n");
+ } else if ( strcmpi("server",type) == 0 && n == 2 ) {
+ if ( strcmpi("shutdown", command) == 0 || strcmpi("exit",command) == 0 || strcmpi("quit",command) == 0 ) {
+ exit(0);
+ }
+ } else if ( strcmpi("help",type) == 0 ) {
+ printf("To use GM commands:\n");
+ printf("admin:<gm command>:<map of \"gm\"> <x> <y>\n");
+ printf("You can use any GM command that doesn't require the GM.\n");
+ printf("No using @item or @warp however you can use @charwarp\n");
+ printf("The <map of \"gm\"> <x> <y> is for commands that need coords of the GM\n");
+ printf("IE: @spawn\n");
+ printf("To shutdown the server:\n");
+ printf("server:shutdown\n");
+ }
+
+ end:
+ free(buf);
+ free(type);
+ free(command);
+ free(map);
+ free(buf2);
+ free(sd);
+
+ return 0;
+}
+
+/*==========================================
+ * 設定ファイルを読み込む
+ *------------------------------------------
+ */
+int map_config_read(char *cfgName) {
+ char line[1024], w1[1024], w2[1024];
+ FILE *fp;
+ struct hostent *h = NULL;
+
+ fp = fopen(cfgName,"r");
+ if (fp == NULL) {
+ printf("Map configuration file not found at: %s\n", cfgName);
+ exit(1);
+ }
+ while(fgets(line, sizeof(line) -1, fp)) {
+ if (line[0] == '/' && line[1] == '/')
+ continue;
+ if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) == 2) {
+ if (strcmpi(w1, "userid")==0){
+ chrif_setuserid(w2);
+ } else if (strcmpi(w1, "passwd") == 0) {
+ chrif_setpasswd(w2);
+ } else if (strcmpi(w1, "char_ip") == 0) {
+ char_ip_set_ = 1;
+ h = gethostbyname (w2);
+ if(h != NULL) {
+ printf("Character server IP address : %s -> %d.%d.%d.%d\n", w2, (unsigned char)h->h_addr[0], (unsigned char)h->h_addr[1], (unsigned char)h->h_addr[2], (unsigned char)h->h_addr[3]);
+ sprintf(w2,"%d.%d.%d.%d", (unsigned char)h->h_addr[0], (unsigned char)h->h_addr[1], (unsigned char)h->h_addr[2], (unsigned char)h->h_addr[3]);
+ }
+ chrif_setip(w2);
+ } else if (strcmpi(w1, "char_port") == 0) {
+ chrif_setport(atoi(w2));
+ } else if (strcmpi(w1, "map_ip") == 0) {
+ map_ip_set_ = 1;
+ h = gethostbyname (w2);
+ if (h != NULL) {
+ printf("Map server IP address : %s -> %d.%d.%d.%d\n", w2, (unsigned char)h->h_addr[0], (unsigned char)h->h_addr[1], (unsigned char)h->h_addr[2], (unsigned char)h->h_addr[3]);
+ sprintf(w2, "%d.%d.%d.%d", (unsigned char)h->h_addr[0], (unsigned char)h->h_addr[1], (unsigned char)h->h_addr[2], (unsigned char)h->h_addr[3]);
+ }
+ clif_setip(w2);
+ } else if (strcmpi(w1, "map_port") == 0) {
+ clif_setport(atoi(w2));
+ map_port = (atoi(w2));
+ } else if (strcmpi(w1, "water_height") == 0) {
+ map_readwater(w2);
+ } else if (strcmpi(w1, "map") == 0) {
+ map_addmap(w2);
+ } else if (strcmpi(w1, "delmap") == 0) {
+ map_delmap(w2);
+ } else if (strcmpi(w1, "npc") == 0) {
+ npc_addsrcfile(w2);
+ } else if (strcmpi(w1, "delnpc") == 0) {
+ npc_delsrcfile(w2);
+ } else if (strcmpi(w1, "data_grf") == 0) {
+ grfio_setdatafile(w2);
+ } else if (strcmpi(w1, "sdata_grf") == 0) {
+ grfio_setsdatafile(w2);
+ } else if (strcmpi(w1, "adata_grf") == 0) {
+ grfio_setadatafile(w2);
+ } else if (strcmpi(w1, "autosave_time") == 0) {
+ autosave_interval = atoi(w2) * 1000;
+ if (autosave_interval <= 0)
+ autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
+ } else if (strcmpi(w1, "motd_txt") == 0) {
+ strcpy(motd_txt, w2);
+ } else if (strcmpi(w1, "help_txt") == 0) {
+ strcpy(help_txt, w2);
+ } else if (strcmpi(w1, "mapreg_txt") == 0) {
+ strcpy(mapreg_txt, w2);
+ } else if (strcmpi(w1, "import") == 0) {
+ map_config_read(w2);
+ } else if (strcmpi(w1, "console") == 0) {
+ if(strcmpi(w2,"on") == 0 || strcmpi(w2,"yes") == 0 )
+ console = 1;
+ } else if(strcmpi(w1,"imalive_on")==0){ //Added by Mugendai for I'm Alive mod
+ imalive_on = atoi(w2); //Added by Mugendai for I'm Alive mod
+ } else if(strcmpi(w1,"imalive_time")==0){ //Added by Mugendai for I'm Alive mod
+ imalive_time = atoi(w2); //Added by Mugendai for I'm Alive mod
+ } else if(strcmpi(w1,"flush_on")==0){ //Added by Mugendai for GUI
+ flush_on = atoi(w2); //Added by Mugendai for GUI
+ } else if(strcmpi(w1,"flush_time")==0){ //Added by Mugendai for GUI
+ flush_time = atoi(w2); //Added by Mugendai for GUI
+ }
+
+ }
+ }
+ fclose(fp);
+
+ return 0;
+}
+
+#ifndef TXT_ONLY
+/*=======================================
+ * MySQL Init
+ *---------------------------------------
+ */
+
+int map_sql_init(void){
+
+ mysql_init(&mmysql_handle);
+
+ //DB connection start
+ printf("Connect Map DB Server....\n");
+ if(!mysql_real_connect(&mmysql_handle, map_server_ip, map_server_id, map_server_pw,
+ map_server_db ,map_server_port, (char *)NULL, 0)) {
+ //pointer check
+ printf("%s\n",mysql_error(&mmysql_handle));
+ exit(1);
+ }
+ else {
+ printf ("connect success! (Map Server Connection)\n");
+ }
+
+ mysql_init(&lmysql_handle);
+
+ //DB connection start
+ printf("Connect Login DB Server....\n");
+ if(!mysql_real_connect(&lmysql_handle, login_server_ip, login_server_id, login_server_pw,
+ login_server_db ,login_server_port, (char *)NULL, 0)) {
+ //pointer check
+ printf("%s\n",mysql_error(&lmysql_handle));
+ exit(1);
+ }
+ else {
+ printf ("connect success! (Login Server Connection)\n");
+ }
+
+ if(battle_config.mail_system) { // mail system [Valaris]
+ mysql_init(&mail_handle);
+ if(!mysql_real_connect(&mail_handle, map_server_ip, map_server_id, map_server_pw,
+ map_server_db ,map_server_port, (char *)NULL, 0)) {
+ printf("%s\n",mysql_error(&mail_handle));
+ exit(1);
+ }
+ }
+
+ return 0;
+}
+
+int map_sql_close(void){
+ mysql_close(&mmysql_handle);
+ printf("Close Map DB Connection....\n");
+
+ mysql_close(&lmysql_handle);
+ printf("Close Login DB Connection....\n");
+ return 0;
+}
+
+int log_sql_init(void){
+
+ mysql_init(&mmysql_handle);
+
+ //DB connection start
+ printf("\033[1;29m[SQL]\033[0;0m: Connecting to Log Database \033[1;29m%s\033[0;0m At \033[1;29m%s\033[0;0m...\n",log_db,log_db_ip);
+ if(!mysql_real_connect(&mmysql_handle, log_db_ip, log_db_id, log_db_pw,
+ log_db ,log_db_port, (char *)NULL, 0)) {
+ //pointer check
+ printf("\033[1;29m[SQL Error]\033[0;0m: %s\n",mysql_error(&mmysql_handle));
+ exit(1);
+ } else {
+ printf("\033[1;29m[SQL]\033[0;0m: Successfully \033[1;32mconnected\033[0;0m to Database \033[1;29m%s\033[0;0m.\n", log_db);
+ }
+
+ return 0;
+}
+
+int sql_config_read(char *cfgName)
+{
+ int i;
+ char line[1024],w1[1024],w2[1024];
+ FILE *fp;
+
+ fp=fopen(cfgName,"r");
+ if(fp==NULL){
+ printf("file not found: %s\n",cfgName);
+ return 1;
+ }
+ while(fgets(line,1020,fp)){
+ if(line[0] == '/' && line[1] == '/')
+ continue;
+ i=sscanf(line,"%[^:]: %[^\r\n]",w1,w2);
+ if(i!=2)
+ continue;
+ if(strcmpi(w1,"item_db_db")==0){
+ strcpy(item_db_db,w2);
+ } else if(strcmpi(w1,"mob_db_db")==0){
+ strcpy(mob_db_db,w2);
+ } else if(strcmpi(w1,"login_db_level")==0){
+ strcpy(login_db_level,w2);
+ } else if(strcmpi(w1,"login_db_account_id")==0){
+ strcpy(login_db_account_id,w2);
+ } else if(strcmpi(w1,"login_db")==0){
+ strcpy(login_db,w2);
+ } else if (strcmpi(w1, "char_db") == 0) {
+ strcpy(char_db, w2);
+ } else if(strcmpi(w1,"gm_db_level")==0){
+ strcpy(gm_db_level,w2);
+ } else if(strcmpi(w1,"gm_db_account_id")==0){
+ strcpy(gm_db_account_id,w2);
+ } else if(strcmpi(w1,"gm_db")==0){
+ strcpy(gm_db,w2);
+ //Map Server SQL DB
+ } else if(strcmpi(w1,"map_server_ip")==0){
+ strcpy(map_server_ip, w2);
+ printf ("set map_server_ip : %s\n",w2);
+ } else if(strcmpi(w1,"map_server_port")==0){
+ map_server_port=atoi(w2);
+ printf ("set map_server_port : %s\n",w2);
+ } else if(strcmpi(w1,"map_server_id")==0){
+ strcpy(map_server_id, w2);
+ printf ("set map_server_id : %s\n",w2);
+ } else if(strcmpi(w1,"map_server_pw")==0){
+ strcpy(map_server_pw, w2);
+ printf ("set map_server_pw : %s\n",w2);
+ } else if(strcmpi(w1,"map_server_db")==0){
+ strcpy(map_server_db, w2);
+ printf ("set map_server_db : %s\n",w2);
+ //Map server option to use SQL db or not
+ } else if(strcmpi(w1,"use_sql_db")==0){
+ if (strcmpi(w2,"yes")){db_use_sqldbs=0;} else if (strcmpi(w2,"no")){db_use_sqldbs=1;}
+ printf ("Using SQL dbs: %s\n",w2);
+ //Login Server SQL DB
+ } else if(strcmpi(w1,"login_server_ip")==0){
+ strcpy(login_server_ip, w2);
+ printf ("set login_server_ip : %s\n",w2);
+ } else if(strcmpi(w1,"login_server_port")==0){
+ login_server_port = atoi(w2);
+ printf ("set login_server_port : %s\n",w2);
+ } else if(strcmpi(w1,"login_server_id")==0){
+ strcpy(login_server_id, w2);
+ printf ("set login_server_id : %s\n",w2);
+ } else if(strcmpi(w1,"login_server_pw")==0){
+ strcpy(login_server_pw, w2);
+ printf ("set login_server_pw : %s\n",w2);
+ } else if(strcmpi(w1,"login_server_db")==0){
+ strcpy(login_server_db, w2);
+ printf ("set login_server_db : %s\n",w2);
+ } else if(strcmpi(w1,"lowest_gm_level")==0){
+ lowest_gm_level = atoi(w2);
+ printf ("set lowest_gm_level : %s\n",w2);
+ } else if(strcmpi(w1,"read_gm_interval")==0){
+ read_gm_interval = ( atoi(w2) * 60 * 1000 ); // Minutes multiplied by 60 secs per min by 1000 milliseconds per second
+ printf ("set read_gm_interval : %s\n",w2);
+ } else if(strcmpi(w1,"log_db")==0) {
+ strcpy(log_db, w2);
+ } else if(strcmpi(w1,"log_db_ip")==0) {
+ strcpy(log_db_ip, w2);
+ } else if(strcmpi(w1,"log_db")==0) {
+ strcpy(log_db, w2);
+ } else if(strcmpi(w1,"log_db_id")==0) {
+ strcpy(log_db_id, w2);
+ } else if(strcmpi(w1,"log_db_pw")==0) {
+ strcpy(log_db_pw, w2);
+ } else if(strcmpi(w1,"log_db_port")==0) {
+ log_db_port = atoi(w2);
+ }
+ }
+ fclose(fp);
+
+ return 0;
+}
+
+// sql online status checking [Valaris]
+void char_offline(struct map_session_data *sd)
+{
+ if(sd && sd->status.char_id) {
+ sprintf(tmp_sql,"UPDATE `%s` SET `online`='0' WHERE `char_id`='%d'", char_db, sd->status.char_id);
+ if(mysql_query(&mmysql_handle, tmp_sql) ) {
+ printf("DB server Error (update online `%s`)- %s\n", char_db, mysql_error(&mmysql_handle) );
+ }
+ }
+}
+
+void do_reset_online(void)
+{
+ sprintf(tmp_sql,"UPDATE `%s` SET `online`='0' WHERE `online`='1'", char_db);
+ if(mysql_query(&mmysql_handle, tmp_sql) ) {
+ printf("DB server Error (reset_online `%s`)- %s\n", char_db, mysql_error(&mmysql_handle) );
+ }
+}
+
+int online_timer(int tid,unsigned int tick,int id,int data)
+{
+ if(check_online_timer != tid)
+ return 0;
+
+ char_online_check();
+
+ check_online_timer=add_timer(gettick()+CHECK_INTERVAL,online_timer,0,0);
+
+ return 0;
+}
+
+void char_online_check(void)
+{
+ int i;
+ struct map_session_data *sd=NULL;
+
+ do_reset_online();
+
+ for(i=0;i<fd_max;i++){
+ if (session[i] && (sd = session[i]->session_data) && sd && sd->state.auth &&
+ !(battle_config.hide_GM_session && pc_isGM(sd)))
+ if(sd->status.char_id) {
+ sprintf(tmp_sql,"UPDATE `%s` SET `online`='1' WHERE `char_id`='%d'", char_db, sd->status.char_id);
+ if(mysql_query(&mmysql_handle, tmp_sql) ) {
+ printf("DB server Error (update online `%s`)- %s\n", char_db, mysql_error(&mmysql_handle) );
+ }
+ }
+ }
+
+
+ if(check_online_timer && check_online_timer != -1) {
+ delete_timer(check_online_timer,online_timer);
+ add_timer(gettick()+CHECK_INTERVAL,online_timer,0,0);
+ }
+
+}
+
+#endif /* not TXT_ONLY */
+
+//-----------------------------------------------------
+//I'm Alive Alert
+//Used to output 'I'm Alive' every few seconds
+//Intended to let frontends know if the app froze
+//-----------------------------------------------------
+int imalive_timer(int tid, unsigned int tick, int id, int data){
+ printf("I'm Alive\n");
+ return 0;
+}
+
+//-----------------------------------------------------
+//Flush stdout
+//stdout buffer needs flushed to be seen in GUI
+//-----------------------------------------------------
+int flush_timer(int tid, unsigned int tick, int id, int data){
+ fflush(stdout);
+ return 0;
+}
+
+int id_db_final(void *k,void *d,va_list ap){ return 0; }
+int map_db_final(void *k,void *d,va_list ap){ return 0; }
+int nick_db_final(void *k,void *d,va_list ap){ return 0; }
+int charid_db_final(void *k,void *d,va_list ap){ return 0; }
+
+static int cleanup_sub(struct block_list *bl, va_list ap) {
+ nullpo_retr(0, bl);
+
+ switch(bl->type) {
+ case BL_PC:
+ map_delblock(bl); // There is something better...
+ break;
+ case BL_NPC:
+ npc_delete((struct npc_data *)bl);
+ break;
+ case BL_MOB:
+ mob_delete((struct mob_data *)bl);
+ break;
+ case BL_PET:
+ pet_remove_map((struct map_session_data *)bl);
+ break;
+ case BL_ITEM:
+ map_clearflooritem(bl->id);
+ break;
+ case BL_SKILL:
+ skill_delunit((struct skill_unit *) bl);
+ break;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * map鯖終了時処理
+ *------------------------------------------
+ */
+void do_final(void) {
+ int map_id, i;
+
+ for (map_id = 0; map_id < map_num;map_id++) {
+ if(map[map_id].m)
+ map_foreachinarea(cleanup_sub, map_id, 0, 0, map[map_id].xs, map[map_id].ys, 0, 0);
+ }
+
+ for (i = 0; i < fd_max; i++)
+ delete_session(i);
+
+ map_removenpc();
+ timer_final();
+
+ numdb_final(id_db, id_db_final);
+ strdb_final(map_db, map_db_final);
+ strdb_final(nick_db, nick_db_final);
+ numdb_final(charid_db, charid_db_final);
+
+ for(i=0;i<=map_num;i++){
+ if(map[i].gat) free(map[i].gat);
+ if(map[i].block) free(map[i].block);
+ if(map[i].block_mob) free(map[i].block_mob);
+ if(map[i].block_count) free(map[i].block_count);
+ if(map[i].block_mob_count) free(map[i].block_mob_count);
+ }
+ do_final_script();
+ do_final_itemdb();
+ do_final_storage();
+ do_final_guild();
+#ifndef TXT_ONLY
+ do_reset_online();
+ map_sql_close();
+#endif /* not TXT_ONLY */
+}
+
+void map_helpscreen() {
+ exit(1);
+}
+
+/*======================================================
+ * Map-Server Init and Command-line Arguments [Valaris]
+ *------------------------------------------------------
+ */
+int do_init(int argc, char *argv[]) {
+ int i;
+
+#ifndef TXT_ONLY
+ unsigned char *SQL_CONF_NAME="conf/inter_athena.conf";
+ unsigned char *LOG_CONF_NAME="conf/log_athena.conf";
+#endif
+ unsigned char *MAP_CONF_NAME = "conf/map_athena.conf";
+ unsigned char *BATTLE_CONF_FILENAME = "conf/battle_athena.conf";
+ unsigned char *ATCOMMAND_CONF_FILENAME = "conf/atcommand_athena.conf";
+ unsigned char *SCRIPT_CONF_NAME = "conf/script_athena.conf";
+ unsigned char *MSG_CONF_NAME = "conf/msg_athena.conf";
+ unsigned char *GRF_PATH_FILENAME = "conf/grf-files.txt";
+
+ srand(gettick());
+
+ for (i = 1; i < argc ; i++) {
+
+ if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "--h") == 0 || strcmp(argv[i], "--?") == 0 || strcmp(argv[i], "/?") == 0)
+ map_helpscreen();
+ else if (strcmp(argv[i], "--map_config") == 0)
+ MAP_CONF_NAME=argv[i+1];
+ else if (strcmp(argv[i],"--battle_config") == 0)
+ BATTLE_CONF_FILENAME = argv[i+1];
+ else if (strcmp(argv[i],"--atcommand_config") == 0)
+ ATCOMMAND_CONF_FILENAME = argv[i+1];
+ else if (strcmp(argv[i],"--script_config") == 0)
+ SCRIPT_CONF_NAME = argv[i+1];
+ else if (strcmp(argv[i],"--msg_config") == 0)
+ MSG_CONF_NAME = argv[i+1];
+ else if (strcmp(argv[i],"--grf_path_file") == 0)
+ GRF_PATH_FILENAME = argv[i+1];
+#ifndef TXT_ONLY
+ else if (strcmp(argv[i],"--sql_config") == 0)
+ SQL_CONF_NAME = argv[i+1];
+#endif /* not TXT_ONLY */
+ }
+
+ map_config_read(MAP_CONF_NAME);
+
+ if ((naddr_ == 0) && (map_ip_set_ == 0 || char_ip_set_ == 0)) {
+ printf("\nUnable to determine your IP address... please edit\n");
+ printf("the map_athena.conf file and set it.\n");
+ printf("(127.0.0.1 is valid if you have no network interface)\n");
+ }
+
+ if (map_ip_set_ == 0 || char_ip_set_ == 0) {
+ // The map server should know what IP address it is running on
+ // - MouseJstr
+ int localaddr = ntohl(addr_[0]);
+ unsigned char *ptr = (unsigned char *) &localaddr;
+ char buf[16];
+ sprintf(buf, "%d.%d.%d.%d", ptr[0], ptr[1], ptr[2], ptr[3]);;
+ if (naddr_ != 1)
+ printf("Multiple interfaces detected.. using %s as our IP address\n", buf);
+ else
+ printf("Defaulting to %s as our IP address\n", buf);
+ if (map_ip_set_ == 0)
+ clif_setip(buf);
+ if (char_ip_set_ == 0)
+ chrif_setip(buf);
+
+ if (ptr[0] == 192 && ptr[1] == 168)
+ printf("\nFirewall detected.. \n edit lan_support.conf and map_athena.conf\n\n");
+ }
+
+ battle_config_read(BATTLE_CONF_FILENAME);
+ atcommand_config_read(ATCOMMAND_CONF_FILENAME);
+ script_config_read(SCRIPT_CONF_NAME);
+ msg_config_read(MSG_CONF_NAME);
+#ifndef TXT_ONLY
+ sql_config_read(SQL_CONF_NAME);
+ log_config_read(LOG_CONF_NAME);
+#endif /* not TXT_ONLY */
+
+ atexit(do_final);
+
+ id_db = numdb_init();
+ map_db = strdb_init(16);
+ nick_db = strdb_init(24);
+ charid_db = numdb_init();
+#ifndef TXT_ONLY
+ map_sql_init();
+#endif /* not TXT_ONLY */
+
+ grfio_init(GRF_PATH_FILENAME);
+
+ map_readallmap();
+
+ add_timer_func_list(map_clearflooritem_timer, "map_clearflooritem_timer");
+
+ //Added by Mugendai for GUI support
+ if (flush_on)
+ {
+ add_timer_interval(gettick()+10, flush_timer,0,0,flush_time);
+ }
+
+#ifndef TXT_ONLY // online status timer, checks every hour [Valaris]
+ add_timer_func_list(online_timer, "online_timer");
+ check_online_timer=add_timer(gettick()+CHECK_INTERVAL,online_timer,0,0);
+#endif /* not TXT_ONLY */
+
+ do_init_chrif();
+ do_init_clif();
+ do_init_itemdb();
+ do_init_mob(); // npcの初期化時内でmob_spawnして、mob_dbを参照するのでinit_npcより先
+ do_init_script();
+ do_init_npc();
+ do_init_pc();
+ do_init_party();
+ do_init_guild();
+ do_init_storage();
+ do_init_skill();
+ do_init_pet();
+
+#ifndef TXT_ONLY /* mail system [Valaris] */
+ if(battle_config.mail_system)
+ do_init_mail();
+
+ if (log_config.branch || log_config.drop || log_config.mvpdrop ||
+ log_config.present || log_config.produce || log_config.refine ||
+ log_config.trade)
+ {
+ log_sql_init();
+ }
+#endif /* not TXT_ONLY */
+
+ npc_event_do_oninit(); // npcのOnInitイベント実行
+
+ if ( console ) {
+ set_defaultconsoleparse(parse_console);
+ start_console();
+ }
+
+ if (battle_config.pk_mode == 1)
+ printf("The server is running in \033[1;31mPK Mode\033[0m.\n");
+
+ //Added for Mugendais I'm Alive mod
+ if (imalive_on)
+ add_timer_interval(gettick()+10, imalive_timer,0,0,imalive_time*1000);
+
+ printf("The map-server is \033[1;32mready\033[0m (Server is listening on the port %d).\n\n", map_port);
+ ticks = gettick();
+
+
+ return 0;
+}
diff --git a/src/map/map.h b/src/map/map.h
new file mode 100644
index 000000000..6e7f6c7e5
--- /dev/null
+++ b/src/map/map.h
@@ -0,0 +1,724 @@
+// $Id: map.h,v 1.8 2004/09/25 11:39:17 MouseJstr Exp $
+#ifndef _MAP_H_
+#define _MAP_H_
+
+#include <stdarg.h>
+#include "mmo.h"
+
+#define MAX_PC_CLASS (1+6+6+1+6+1+1+1+1+4023)
+#define PC_CLASS_BASE 0
+#define PC_CLASS_BASE2 (PC_CLASS_BASE + 4001)
+#define PC_CLASS_BASE3 (PC_CLASS_BASE2 + 22)
+#define MAX_NPC_PER_MAP 512
+#define BLOCK_SIZE 8
+#define AREA_SIZE battle_config.area_size
+#define LOCAL_REG_NUM 16
+#define LIFETIME_FLOORITEM 60
+#define DAMAGELOG_SIZE 30
+#define LOOTITEM_SIZE 10
+#define MAX_SKILL_LEVEL 100
+#define MAX_STATUSCHANGE 200
+#define MAX_SKILLUNITGROUP 32
+#define MAX_MOBSKILLUNITGROUP 8
+#define MAX_SKILLUNITGROUPTICKSET 128
+#define MAX_SKILLTIMERSKILL 32
+#define MAX_MOBSKILLTIMERSKILL 10
+#define MAX_MOBSKILL 32
+#define MAX_EVENTQUEUE 2
+#define MAX_EVENTTIMER 32
+#define NATURAL_HEAL_INTERVAL 500
+#define MAX_FLOORITEM 500000
+#define MAX_LEVEL 255
+#define MAX_WALKPATH 48
+#define MAX_DROP_PER_MAP 48
+#define MAX_WIS_REFUSAL 14
+
+#define DEFAULT_AUTOSAVE_INTERVAL 60*1000
+
+#define OPTION_HIDE 0x40
+
+enum { BL_NUL, BL_PC, BL_NPC, BL_MOB, BL_ITEM, BL_CHAT, BL_SKILL , BL_PET };
+enum { WARP, SHOP, SCRIPT, MONS };
+
+struct block_list {
+ struct block_list *next,*prev;
+ int id;
+ short m,x,y;
+ unsigned char type;
+ unsigned char subtype;
+};
+
+struct walkpath_data {
+ unsigned char path_len,path_pos,path_half;
+ unsigned char path[MAX_WALKPATH];
+};
+struct script_reg {
+ int index;
+ int data;
+};
+struct script_regstr {
+ int index;
+ char data[256];
+};
+struct status_change {
+ int timer;
+ int val1,val2,val3,val4;
+};
+struct vending {
+ short index;
+ unsigned short amount;
+ unsigned int value;
+};
+
+struct skill_unit_group;
+struct skill_unit {
+ struct block_list bl;
+
+ struct skill_unit_group *group;
+
+ int limit;
+ int val1,val2;
+ short alive,range;
+};
+struct skill_unit_group {
+ int src_id;
+ int party_id;
+ int guild_id;
+ int map,range;
+ int target_flag;
+ unsigned int tick;
+ int limit,interval;
+
+ int skill_id,skill_lv;
+ int val1,val2;
+ char *valstr;
+ int unit_id;
+ int group_id;
+ int unit_count,alive_count;
+ struct skill_unit *unit;
+};
+struct skill_unit_group_tickset {
+ unsigned int tick;
+ int group_id;
+};
+struct skill_timerskill {
+ int timer;
+ int src_id;
+ int target_id;
+ int map;
+ short x,y;
+ short skill_id,skill_lv;
+ int type;
+ int flag;
+};
+
+struct npc_data;
+struct pet_db;
+struct item_data;
+struct square;
+
+struct map_session_data {
+ struct block_list bl;
+ struct {
+ unsigned auth : 1;
+ unsigned change_walk_target : 1;
+ unsigned attack_continue : 1;
+ unsigned menu_or_input : 1;
+ unsigned dead_sit : 2;
+ unsigned skillcastcancel : 1;
+ unsigned waitingdisconnect : 1;
+ unsigned lr_flag : 2;
+ unsigned connect_new : 1;
+ unsigned arrow_atk : 1;
+ unsigned attack_type : 3;
+ unsigned skill_flag : 1;
+ unsigned gangsterparadise : 1;
+ unsigned produce_flag : 1;
+ unsigned make_arrow_flag : 1;
+ unsigned potionpitcher_flag : 1;
+ unsigned storage_flag : 1;
+ } state;
+ struct {
+ unsigned killer : 1;
+ unsigned killable : 1;
+ unsigned restart_full_recover : 1;
+ unsigned no_castcancel : 1;
+ unsigned no_castcancel2 : 1;
+ unsigned no_sizefix : 1;
+ unsigned no_magic_damage : 1;
+ unsigned no_weapon_damage : 1;
+ unsigned no_gemstone : 1;
+ unsigned infinite_endure : 1;
+ unsigned unbreakable_weapon : 1;
+ unsigned unbreakable_armor : 1;
+ unsigned infinite_autospell : 1;
+ } special_state;
+ int char_id, login_id1, login_id2, sex;
+ int packet_ver; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04 (by [Yor])
+ struct mmo_charstatus status;
+ struct item_data *inventory_data[MAX_INVENTORY];
+ short equip_index[11];
+ int weight,max_weight;
+ int cart_weight,cart_max_weight,cart_num,cart_max_num;
+ char mapname[24];
+ int fd,new_fd;
+ short to_x,to_y;
+ short speed,prev_speed;
+ short opt1,opt2,opt3;
+ char dir,head_dir;
+ unsigned int client_tick,server_tick;
+ struct walkpath_data walkpath;
+ int walktimer;
+ int npc_id,areanpc_id,npc_shopid;
+ int npc_pos;
+ int npc_menu;
+ int npc_amount;
+ int npc_stack,npc_stackmax;
+ char *npc_script,*npc_scriptroot;
+ char *npc_stackbuf;
+ char npc_str[256];
+ unsigned int chatID;
+
+ char wis_refusal[MAX_WIS_REFUSAL][24]; //Refuse Whispers
+ int wis_all; //Ignore all Whispers
+
+ int attacktimer;
+ int attacktarget;
+ short attacktarget_lv;
+ unsigned int attackabletime;
+
+ int followtimer; // [MouseJstr]
+ int followtarget;
+
+ short attackrange,attackrange_;
+ int skilltimer;
+ int skilltarget;
+ short skillx,skilly;
+ short skillid,skilllv;
+ short skillitem,skillitemlv;
+ short skillid_old,skilllv_old;
+ short skillid_dance,skilllv_dance;
+ struct skill_unit_group skillunit[MAX_SKILLUNITGROUP];
+ struct skill_unit_group_tickset skillunittick[MAX_SKILLUNITGROUPTICKSET];
+ struct skill_timerskill skilltimerskill[MAX_SKILLTIMERSKILL];
+ int cloneskill_id,cloneskill_lv;
+ int potion_hp,potion_sp,potion_per_hp,potion_per_sp;
+
+ int invincible_timer;
+ unsigned int canact_tick;
+ unsigned int canmove_tick;
+ unsigned int canlog_tick;
+ int hp_sub,sp_sub;
+ int inchealhptick,inchealsptick,inchealspirithptick,inchealspiritsptick;
+// -- moonsoul (new tick for berserk self-damage)
+ int berserkdamagetick;
+ int fame;
+
+ short view_class;
+ short weapontype1,weapontype2;
+ short disguiseflag,disguise; // [Valaris]
+ int paramb[6],paramc[6],parame[6],paramcard[6];
+ int hit,flee,flee2,aspd,amotion,dmotion;
+ int watk,watk2,atkmods[3];
+ int def,def2,mdef,mdef2,critical,matk1,matk2;
+ int atk_ele,def_ele,star,overrefine;
+ int castrate,hprate,sprate,dsprate;
+ int addele[10],addrace[12],addsize[3],subele[10],subrace[12];
+ int addeff[10],addeff2[10],reseff[10];
+ int watk_,watk_2,atkmods_[3],addele_[10],addrace_[12],addsize_[3]; //二刀流のために追加
+ int atk_ele_,star_,overrefine_; //二刀流のために追加
+ int base_atk,atk_rate;
+ int arrow_atk,arrow_ele,arrow_cri,arrow_hit,arrow_range;
+ int arrow_addele[10],arrow_addrace[12],arrow_addsize[3],arrow_addeff[10],arrow_addeff2[10];
+ int nhealhp,nhealsp,nshealhp,nshealsp,nsshealhp,nsshealsp;
+ int aspd_rate,speed_rate,hprecov_rate,sprecov_rate,critical_def,double_rate;
+ int near_attack_def_rate,long_attack_def_rate,magic_def_rate,misc_def_rate;
+ int matk_rate,ignore_def_ele,ignore_def_race,ignore_def_ele_,ignore_def_race_;
+ int ignore_mdef_ele,ignore_mdef_race;
+ int magic_addele[10],magic_addrace[12],magic_subrace[12];
+ int perfect_hit,get_zeny_num;
+ int critical_rate,hit_rate,flee_rate,flee2_rate,def_rate,def2_rate,mdef_rate,mdef2_rate;
+ int def_ratio_atk_ele,def_ratio_atk_ele_,def_ratio_atk_race,def_ratio_atk_race_;
+ int add_damage_class_count,add_damage_class_count_,add_magic_damage_class_count;
+ short add_damage_classid[10],add_damage_classid_[10],add_magic_damage_classid[10];
+ int add_damage_classrate[10],add_damage_classrate_[10],add_magic_damage_classrate[10];
+ short add_def_class_count,add_mdef_class_count;
+ short add_def_classid[10],add_mdef_classid[10];
+ int add_def_classrate[10],add_mdef_classrate[10];
+ short monster_drop_item_count;
+ short monster_drop_itemid[10];
+ int monster_drop_race[10],monster_drop_itemrate[10];
+ int double_add_rate,speed_add_rate,aspd_add_rate,perfect_hit_add, get_zeny_add_num;
+ short splash_range,splash_add_range;
+ short autospell_id,autospell_lv,autospell_rate;
+ short hp_drain_rate,hp_drain_per,sp_drain_rate,sp_drain_per;
+ short hp_drain_rate_,hp_drain_per_,sp_drain_rate_,sp_drain_per_;
+ int short_weapon_damage_return,long_weapon_damage_return;
+ int weapon_coma_ele[10],weapon_coma_race[12];
+ short break_weapon_rate,break_armor_rate;
+ short add_steal_rate;
+
+ short spiritball, spiritball_old;
+ int spirit_timer[MAX_SKILL_LEVEL];
+ int magic_damage_return; // AppleGirl Was Here
+ int random_attack_increase_add,random_attack_increase_per; // [Valaris]
+ int perfect_hiding; // [Valaris]
+ int unbreakable;
+
+ int die_counter;
+ short doridori_counter;
+
+ int reg_num;
+ struct script_reg *reg;
+ int regstr_num;
+ struct script_regstr *regstr;
+
+ struct status_change sc_data[MAX_STATUSCHANGE];
+ short sc_count;
+ struct square dev;
+
+ int trade_partner;
+ int deal_item_index[10];
+ int deal_item_amount[10];
+ int deal_zeny;
+ short deal_locked;
+
+ int party_sended,party_invite,party_invite_account;
+ int party_hp,party_x,party_y;
+
+ int guild_sended,guild_invite,guild_invite_account;
+ int guild_emblem_id,guild_alliance,guild_alliance_account;
+ int guildspy; // [Syrus22]
+ int partyspy; // [Syrus22]
+
+ int vender_id;
+ int vend_num;
+ char message[80];
+ struct vending vending[12];
+
+ int catch_target_class;
+ struct s_pet pet;
+ struct pet_db *petDB;
+ struct pet_data *pd;
+ int pet_hungry_timer;
+
+ int pvp_point,pvp_rank,pvp_timer,pvp_lastusers;
+
+ char eventqueue[MAX_EVENTQUEUE][50];
+ int eventtimer[MAX_EVENTTIMER];
+
+ int last_skillid,last_skilllv; // Added by RoVeRT
+ short sg_count;
+
+#ifndef TXT_ONLY
+ int mail_counter; // mail counter for mail system [Valaris]
+#endif
+
+};
+
+struct npc_timerevent_list {
+ int timer,pos;
+};
+struct npc_label_list {
+ char name[24];
+ int pos;
+};
+struct npc_item_list {
+ int nameid,value;
+};
+struct npc_data {
+ struct block_list bl;
+ short n;
+ short class,dir;
+ short speed;
+ char name[24];
+ char exname[24];
+ int chat_id;
+ short opt1,opt2,opt3,option;
+ short flag;
+ int walktimer; // [Valaris]
+ short to_x,to_y; // [Valaris]
+ struct walkpath_data walkpath;
+ unsigned int next_walktime;
+ unsigned int canmove_tick;
+
+ struct { // [Valaris]
+ unsigned state : 8;
+ unsigned change_walk_target : 1;
+ unsigned walk_easy : 1;
+ } state;
+
+ union {
+ struct {
+ char *script;
+ short xs,ys;
+ int guild_id;
+ int timer,timerid,timeramount,nexttimer;
+ unsigned int timertick;
+ struct npc_timerevent_list *timer_event;
+ int label_list_num;
+ struct npc_label_list *label_list;
+ int src_id;
+ } scr;
+ struct npc_item_list shop_item[1];
+ struct {
+ short xs,ys;
+ short x,y;
+ char name[16];
+ } warp;
+ } u;
+ // ここにメンバを追加してはならない(shop_itemが可変長の為)
+
+ char eventqueue[MAX_EVENTQUEUE][50];
+ int eventtimer[MAX_EVENTTIMER];
+ short arenaflag;
+};
+struct mob_data {
+ struct block_list bl;
+ short n;
+ short base_class,class,dir,mode;
+ short m,x0,y0,xs,ys;
+ char name[24];
+ int spawndelay1,spawndelay2;
+ struct {
+ unsigned state : 8;
+ unsigned skillstate : 8;
+ unsigned targettype : 1;
+ unsigned steal_flag : 1;
+ unsigned steal_coin_flag : 1;
+ unsigned skillcastcancel : 1;
+ unsigned master_check : 1;
+ unsigned change_walk_target : 1;
+ unsigned walk_easy : 1;
+ unsigned special_mob_ai : 3;
+ } state;
+ int timer;
+ short to_x,to_y;
+ short speed;
+ int hp;
+ int target_id,attacked_id;
+ short target_lv;
+ struct walkpath_data walkpath;
+ unsigned int next_walktime;
+ unsigned int attackabletime;
+ unsigned int last_deadtime,last_spawntime,last_thinktime;
+ unsigned int canmove_tick;
+ short move_fail_count;
+ struct {
+ int id;
+ int dmg;
+ } dmglog[DAMAGELOG_SIZE];
+ struct item *lootitem;
+ short lootitem_count;
+
+ struct status_change sc_data[MAX_STATUSCHANGE];
+ short sc_count;
+ short opt1,opt2,opt3,option;
+ short min_chase;
+ short sg_count;
+ int guild_id;
+ int deletetimer;
+
+ int skilltimer;
+ int skilltarget;
+ short skillx,skilly;
+ short skillid,skilllv,skillidx;
+ unsigned int skilldelay[MAX_MOBSKILL];
+ int def_ele;
+ int master_id,master_dist;
+ int exclusion_src,exclusion_party,exclusion_guild;
+ struct skill_timerskill skilltimerskill[MAX_MOBSKILLTIMERSKILL];
+ struct skill_unit_group skillunit[MAX_MOBSKILLUNITGROUP];
+ struct skill_unit_group_tickset skillunittick[MAX_SKILLUNITGROUPTICKSET];
+ char npc_event[50];
+ short size;
+};
+struct pet_data {
+ struct block_list bl;
+ short n;
+ short class,dir;
+ short speed;
+ char name[24];
+ struct {
+ unsigned state : 8 ;
+ unsigned skillstate : 8 ;
+ unsigned change_walk_target : 1 ;
+ } state;
+ int timer;
+ short to_x,to_y;
+ short equip;
+ struct walkpath_data walkpath;
+ int target_id;
+ short target_lv;
+ int move_fail_count;
+ unsigned int attackabletime,next_walktime,last_thinktime;
+ int skilltype,skillval,skilltimer,skillduration; // [Valaris]
+ int skillbonustype,skillbonusval,skillbonustimer,skillbonusduration; // [Valaris]
+ struct item *lootitem;
+ short loot; // [Valaris]
+ short lootmax; // [Valaris]
+ short lootitem_count;
+ short lootitem_weight;
+ int lootitem_timer;
+ struct skill_timerskill skilltimerskill[MAX_MOBSKILLTIMERSKILL]; // [Valaris]
+ struct skill_unit_group skillunit[MAX_MOBSKILLUNITGROUP]; // [Valaris]
+ struct skill_unit_group_tickset skillunittick[MAX_SKILLUNITGROUPTICKSET]; // [Valaris]
+ struct map_session_data *msd;
+};
+
+enum { MS_IDLE,MS_WALK,MS_ATTACK,MS_DEAD,MS_DELAY };
+
+enum { NONE_ATTACKABLE,ATTACKABLE };
+
+enum { ATK_LUCKY=1,ATK_FLEE,ATK_DEF}; // 囲まれペナルティ計算用
+
+struct map_data {
+ char name[24];
+ char alias[24]; // [MouseJstr]
+ unsigned char *gat; // NULLなら下のmap_data_other_serverとして扱う
+ struct block_list **block;
+ struct block_list **block_mob;
+ int *block_count,*block_mob_count;
+ int m;
+ short xs,ys;
+ short bxs,bys;
+ int npc_num;
+ int users;
+ struct {
+ unsigned alias : 1;
+ unsigned nomemo : 1;
+ unsigned noteleport : 1;
+ unsigned noreturn : 1;
+ unsigned monster_noteleport : 1;
+ unsigned nosave : 1;
+ unsigned nobranch : 1;
+ unsigned nopenalty : 1;
+ unsigned pvp : 1;
+ unsigned pvp_noparty : 1;
+ unsigned pvp_noguild : 1;
+ unsigned pvp_nightmaredrop :1;
+ unsigned pvp_nocalcrank : 1;
+ unsigned gvg : 1;
+ unsigned gvg_noparty : 1;
+ unsigned nozenypenalty : 1;
+ unsigned notrade : 1;
+ unsigned noskill : 1;
+ unsigned nowarp : 1;
+ unsigned nowarpto : 1;
+ unsigned nopvp : 1; // [Valaris]
+ unsigned noicewall : 1; // [Valaris]
+ unsigned snow : 1; // [Valaris]
+ unsigned fog : 1; // [Valaris]
+ unsigned sakura : 1; // [Valaris]
+ unsigned leaves : 1; // [Valaris]
+ unsigned rain : 1; // [Valaris]
+ } flag;
+ struct point save;
+ struct npc_data *npc[MAX_NPC_PER_MAP];
+ struct {
+ int drop_id;
+ int drop_type;
+ int drop_per;
+ } drop_list[MAX_DROP_PER_MAP];
+};
+struct map_data_other_server {
+ char name[24];
+ unsigned char *gat; // NULL固定にして判断
+ unsigned long ip;
+ unsigned int port;
+};
+#define read_gat(m,x,y) (map[m].gat[(x)+(y)*map[m].xs])
+#define read_gatp(m,x,y) (m->gat[(x)+(y)*m->xs])
+
+struct flooritem_data {
+ struct block_list bl;
+ short subx,suby;
+ int cleartimer;
+ int first_get_id,second_get_id,third_get_id;
+ unsigned int first_get_tick,second_get_tick,third_get_tick;
+ struct item item_data;
+};
+
+enum {
+ SP_SPEED,SP_BASEEXP,SP_JOBEXP,SP_KARMA,SP_MANNER,SP_HP,SP_MAXHP,SP_SP, // 0-7
+ SP_MAXSP,SP_STATUSPOINT,SP_0a,SP_BASELEVEL,SP_SKILLPOINT,SP_STR,SP_AGI,SP_VIT, // 8-15
+ SP_INT,SP_DEX,SP_LUK,SP_CLASS,SP_ZENY,SP_SEX,SP_NEXTBASEEXP,SP_NEXTJOBEXP, // 16-23
+ SP_WEIGHT,SP_MAXWEIGHT,SP_1a,SP_1b,SP_1c,SP_1d,SP_1e,SP_1f, // 24-31
+ SP_USTR,SP_UAGI,SP_UVIT,SP_UINT,SP_UDEX,SP_ULUK,SP_26,SP_27, // 32-39
+ SP_28,SP_ATK1,SP_ATK2,SP_MATK1,SP_MATK2,SP_DEF1,SP_DEF2,SP_MDEF1, // 40-47
+ SP_MDEF2,SP_HIT,SP_FLEE1,SP_FLEE2,SP_CRITICAL,SP_ASPD,SP_36,SP_JOBLEVEL, // 48-55
+ SP_UPPER,SP_PARTNER,SP_CART,SP_FAME,SP_UNBREAKABLE, //56-58
+ SP_CARTINFO=99, // 99
+
+ // original 1000-
+ SP_ATTACKRANGE=1000, SP_ATKELE,SP_DEFELE, // 1000-1002
+ SP_CASTRATE, SP_MAXHPRATE, SP_MAXSPRATE, SP_SPRATE, // 1003-1006
+ SP_ADDELE, SP_ADDRACE, SP_ADDSIZE, SP_SUBELE, SP_SUBRACE, // 1007-1011
+ SP_ADDEFF, SP_RESEFF, // 1012-1013
+ SP_BASE_ATK,SP_ASPD_RATE,SP_HP_RECOV_RATE,SP_SP_RECOV_RATE,SP_SPEED_RATE, // 1014-1018
+ SP_CRITICAL_DEF,SP_NEAR_ATK_DEF,SP_LONG_ATK_DEF, // 1019-1021
+ SP_DOUBLE_RATE, SP_DOUBLE_ADD_RATE, SP_MATK, SP_MATK_RATE, // 1022-1025
+ SP_IGNORE_DEF_ELE,SP_IGNORE_DEF_RACE, // 1026-1027
+ SP_ATK_RATE,SP_SPEED_ADDRATE,SP_ASPD_ADDRATE, // 1028-1030
+ SP_MAGIC_ATK_DEF,SP_MISC_ATK_DEF, // 1031-1032
+ SP_IGNORE_MDEF_ELE,SP_IGNORE_MDEF_RACE, // 1033-1034
+ SP_MAGIC_ADDELE,SP_MAGIC_ADDRACE,SP_MAGIC_SUBRACE, // 1035-1037
+ SP_PERFECT_HIT_RATE,SP_PERFECT_HIT_ADD_RATE,SP_CRITICAL_RATE,SP_GET_ZENY_NUM,SP_ADD_GET_ZENY_NUM, // 1038-1042
+ SP_ADD_DAMAGE_CLASS,SP_ADD_MAGIC_DAMAGE_CLASS,SP_ADD_DEF_CLASS,SP_ADD_MDEF_CLASS, // 1043-1046
+ SP_ADD_MONSTER_DROP_ITEM,SP_DEF_RATIO_ATK_ELE,SP_DEF_RATIO_ATK_RACE,SP_ADD_SPEED, // 1047-1050
+ SP_HIT_RATE,SP_FLEE_RATE,SP_FLEE2_RATE,SP_DEF_RATE,SP_DEF2_RATE,SP_MDEF_RATE,SP_MDEF2_RATE, // 1051-1057
+ SP_SPLASH_RANGE,SP_SPLASH_ADD_RANGE,SP_AUTOSPELL,SP_HP_DRAIN_RATE,SP_SP_DRAIN_RATE, // 1058-1062
+ SP_SHORT_WEAPON_DAMAGE_RETURN,SP_LONG_WEAPON_DAMAGE_RETURN,SP_WEAPON_COMA_ELE,SP_WEAPON_COMA_RACE, // 1063-1066
+ SP_ADDEFF2,SP_BREAK_WEAPON_RATE,SP_BREAK_ARMOR_RATE,SP_ADD_STEAL_RATE, // 1067-1070
+ SP_MAGIC_DAMAGE_RETURN,SP_RANDOM_ATTACK_INCREASE,SP_ALL_STATS,SP_AGI_VIT,SP_AGI_DEX_STR,SP_PERFECT_HIDE, // 1071-1077
+ SP_DISGUISE, // 1077
+
+ SP_RESTART_FULL_RECORVER=2000,SP_NO_CASTCANCEL,SP_NO_SIZEFIX,SP_NO_MAGIC_DAMAGE,SP_NO_WEAPON_DAMAGE,SP_NO_GEMSTONE, // 2000-2005
+ SP_NO_CASTCANCEL2,SP_INFINITE_ENDURE,SP_UNBREAKABLE_WEAPON,SP_UNBREAKABLE_ARMOR // 2006-2009
+};
+
+enum {
+ LOOK_BASE,LOOK_HAIR,LOOK_WEAPON,LOOK_HEAD_BOTTOM,LOOK_HEAD_TOP,LOOK_HEAD_MID,LOOK_HAIR_COLOR,LOOK_CLOTHES_COLOR,LOOK_SHIELD,LOOK_SHOES
+};
+
+struct chat_data {
+ struct block_list bl;
+
+ unsigned char pass[8]; /* password */
+ unsigned char title[61]; /* room title MAX 60 */
+ unsigned char limit; /* join limit */
+ unsigned char trigger;
+ unsigned char users; /* current users */
+ unsigned char pub; /* room attribute */
+ struct map_session_data *usersd[20];
+ struct block_list *owner_;
+ struct block_list **owner;
+ char npc_event[50];
+};
+
+extern struct map_data map[];
+extern int map_num;
+extern int autosave_interval;
+extern int agit_flag;
+extern int night_flag; // 0=day, 1=night [Yor]
+
+extern char motd_txt[];
+extern char help_txt[];
+
+extern char talkie_mes[];
+
+extern char wisp_server_name[];
+
+// 鯖全体情報
+void map_setusers(int);
+int map_getusers(void);
+// block削除関連
+int map_freeblock( void *bl );
+int map_freeblock_lock(void);
+int map_freeblock_unlock(void);
+// block関連
+int map_addblock(struct block_list *);
+int map_delblock(struct block_list *);
+void map_foreachinarea(int (*)(struct block_list*,va_list),int,int,int,int,int,int,...);
+// -- moonsoul (added map_foreachincell)
+void map_foreachincell(int (*)(struct block_list*,va_list),int,int,int,int,...);
+void map_foreachinmovearea(int (*)(struct block_list*,va_list),int,int,int,int,int,int,int,int,...);
+int map_countnearpc(int,int,int);
+//block関連に追加
+int map_count_oncell(int m,int x,int y);
+// 一時的object関連
+int map_addobject(struct block_list *);
+int map_delobject(int);
+int map_delobjectnofree(int id);
+void map_foreachobject(int (*)(struct block_list*,va_list),int,...);
+//
+int map_quit(struct map_session_data *);
+// npc
+int map_addnpc(int,struct npc_data *);
+
+// 床アイテム関連
+int map_clearflooritem_timer(int,unsigned int,int,int);
+#define map_clearflooritem(id) map_clearflooritem_timer(0,0,id,1)
+int map_addflooritem(struct item *,int,int,int,int,struct map_session_data *,struct map_session_data *,struct map_session_data *,int);
+int map_searchrandfreecell(int,int,int,int);
+
+// キャラid=>キャラ名 変換関連
+void map_addchariddb(int charid,char *name);
+void map_delchariddb(int charid);
+int map_reqchariddb(struct map_session_data * sd,int charid);
+char * map_charid2nick(int);
+
+struct map_session_data * map_id2sd(int);
+struct block_list * map_id2bl(int);
+int map_mapname2mapid(char*);
+int map_mapname2ipport(char*,int*,int*);
+int map_setipport(char *name,unsigned long ip,int port);
+int map_eraseipport(char *name,unsigned long ip,int port);
+void map_addiddb(struct block_list *);
+void map_deliddb(struct block_list *bl);
+int map_foreachiddb(int (*)(void*,void*,va_list),...);
+void map_addnickdb(struct map_session_data *);
+struct map_session_data * map_nick2sd(char*);
+
+// gat関連
+int map_getcell(int,int,int);
+int map_setcell(int,int,int,int);
+
+// その他
+int map_check_dir(int s_dir,int t_dir);
+int map_calc_dir( struct block_list *src,int x,int y);
+
+// path.cより
+int path_search(struct walkpath_data*,int,int,int,int,int,int);
+int path_blownpos(int m,int x0,int y0,int dx,int dy,int count);
+
+int map_who(int fd);
+
+void map_helpscreen(); // [Valaris]
+int map_delmap(char *mapname);
+
+extern unsigned long ticks;
+
+#ifndef TXT_ONLY
+
+// MySQL
+#include <mysql.h>
+
+void char_online_check(void); // [Valaris]
+void char_offline(struct map_session_data *sd);
+
+extern MYSQL mmysql_handle;
+extern char tmp_sql[65535];
+extern MYSQL_RES* sql_res ;
+extern MYSQL_ROW sql_row ;
+
+extern MYSQL lmysql_handle;
+extern char tmp_lsql[65535];
+extern MYSQL_RES* lsql_res ;
+extern MYSQL_ROW lsql_row ;
+
+extern MYSQL mail_handle;
+extern MYSQL_RES* mail_res ;
+extern MYSQL_ROW mail_row ;
+extern char tmp_msql[65535];
+
+extern int db_use_sqldbs;
+
+extern char item_db_db[32];
+extern char mob_db_db[32];
+extern char login_db[32];
+
+extern char login_db_level[32];
+extern char login_db_account_id[32];
+
+extern char gm_db[32];
+extern char gm_db_level[32];
+extern char gm_db_account_id[32];
+
+extern int lowest_gm_level;
+extern int read_gm_interval;
+
+extern char char_db[32];
+#endif /* not TXT_ONLY */
+
+#endif
diff --git a/src/map/mob.c b/src/map/mob.c
new file mode 100644
index 000000000..46e367371
--- /dev/null
+++ b/src/map/mob.c
@@ -0,0 +1,4269 @@
+// $Id: mob.c,v 1.7 2004/09/25 05:32:18 MouseJstr Exp $
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "timer.h"
+#include "socket.h"
+#include "db.h"
+#include "nullpo.h"
+#include "malloc.h"
+#include "map.h"
+#include "clif.h"
+#include "intif.h"
+#include "pc.h"
+#include "mob.h"
+#include "guild.h"
+#include "itemdb.h"
+#include "skill.h"
+#include "battle.h"
+#include "party.h"
+#include "npc.h"
+#include "log.h"
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+#define MIN_MOBTHINKTIME 100
+
+#define MOB_LAZYMOVEPERC 50 // Move probability in the negligent mode MOB (rate of 1000 minute)
+#define MOB_LAZYWARPPERC 20 // Warp probability in the negligent mode MOB (rate of 1000 minute)
+
+struct mob_db mob_db[2001];
+
+/*==========================================
+ * Local prototype declaration (only required thing)
+ *------------------------------------------
+ */
+static int distance(int,int,int,int);
+static int mob_makedummymobdb(int);
+static int mob_timer(int,unsigned int,int,int);
+int mobskill_use(struct mob_data *md,unsigned int tick,int event);
+int mobskill_deltimer(struct mob_data *md );
+int mob_skillid2skillidx(int class,int skillid);
+int mobskill_use_id(struct mob_data *md,struct block_list *target,int skill_idx);
+static int mob_unlocktarget(struct mob_data *md,int tick);
+
+/*==========================================
+ * Mob is searched with a name.
+ *------------------------------------------
+ */
+int mobdb_searchname(const char *str)
+{
+ int i;
+
+ for(i = 0; i < sizeof(mob_db) / sizeof(mob_db[0]); i++) {
+ if (strcmpi(mob_db[i].name, str) == 0 || strcmp(mob_db[i].jname, str) == 0 ||
+ memcmp(mob_db[i].name, str, 24) == 0 || memcmp(mob_db[i].jname, str, 24) == 0)
+ return i;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * Id Mob is checked.
+ *------------------------------------------
+ */
+int mobdb_checkid(const int id)
+{
+ if (id <= 0 || id >= (sizeof(mob_db) / sizeof(mob_db[0])) || mob_db[id].name[0] == '\0')
+ return 0;
+
+ return id;
+}
+
+/*==========================================
+ * The minimum data set for MOB spawning
+ *------------------------------------------
+ */
+int mob_spawn_dataset(struct mob_data *md,const char *mobname,int class)
+{
+ nullpo_retr(0, md);
+
+ md->bl.prev=NULL;
+ md->bl.next=NULL;
+ if(strcmp(mobname,"--en--")==0)
+ memcpy(md->name,mob_db[class].name,24);
+ else if(strcmp(mobname,"--ja--")==0)
+ memcpy(md->name,mob_db[class].jname,24);
+ else
+ memcpy(md->name,mobname,24);
+
+ md->n = 0;
+ md->base_class = md->class = class;
+ md->bl.id= npc_get_new_npc_id();
+
+ memset(&md->state,0,sizeof(md->state));
+ md->timer = -1;
+ md->target_id=0;
+ md->attacked_id=0;
+ md->speed=mob_db[class].speed;
+
+ return 0;
+}
+
+
+/*==========================================
+ * The MOB appearance for one time (for scripts)
+ *------------------------------------------
+ */
+int mob_once_spawn(struct map_session_data *sd,char *mapname,
+ int x,int y,const char *mobname,int class,int amount,const char *event)
+{
+ struct mob_data *md=NULL;
+ int m,count,lv=255,r=class;
+
+ if( sd )
+ lv=sd->status.base_level;
+
+ if( sd && strcmp(mapname,"this")==0)
+ m=sd->bl.m;
+ else
+ m=map_mapname2mapid(mapname);
+
+ if(m<0 || amount<=0 || (class>=0 && class<=1000) || class>2000) // 値が異常なら召喚を止める
+ return 0;
+
+ if(class<0){ // ランダムに召喚
+ int i=0;
+ int j=-class-1;
+ int k;
+ if(j>=0 && j<MAX_RANDOMMONSTER){
+ do{
+ class=rand()%1000+1001;
+ k=rand()%1000000;
+ }while((mob_db[class].max_hp <= 0 || mob_db[class].summonper[j] <= k ||
+ (lv<mob_db[class].lv && battle_config.random_monster_checklv==1)) && (i++) < 2000);
+ if(i>=2000){
+ class=mob_db[0].summonper[j];
+ }
+ }else{
+ return 0;
+ }
+// if(battle_config.etc_log==1)
+// printf("mobclass=%d try=%d\n",class,i);
+ }
+ if(sd){
+ if(x<=0) x=sd->bl.x;
+ if(y<=0) y=sd->bl.y;
+ }else if(x<=0 || y<=0){
+ printf("mob_once_spawn: ??\n");
+ }
+
+ for(count=0;count<amount;count++){
+ md=(struct mob_data *)aCalloc(1,sizeof(struct mob_data));
+ memset(md, '\0', sizeof *md);
+ if(mob_db[class].mode&0x02)
+ md->lootitem=(struct item *)aCalloc(LOOTITEM_SIZE,sizeof(struct item));
+ else
+ md->lootitem=NULL;
+
+ mob_spawn_dataset(md,mobname,class);
+ md->bl.m=m;
+ md->bl.x=x;
+ md->bl.y=y;
+ if(r<0&&battle_config.dead_branch_active==1) md->mode=0x1+0x4+0x80; //移動してアクティブで反撃する
+ md->m =m;
+ md->x0=x;
+ md->y0=y;
+ md->xs=0;
+ md->ys=0;
+ md->spawndelay1=-1; // Only once is a flag.
+ md->spawndelay2=-1; // Only once is a flag.
+
+ memcpy(md->npc_event,event,sizeof(md->npc_event));
+
+ md->bl.type=BL_MOB;
+ map_addiddb(&md->bl);
+ mob_spawn(md->bl.id);
+
+ if(class==1288) { // emperium hp based on defense level [Valaris]
+ struct guild_castle *gc=guild_mapname2gc(map[md->bl.m].name);
+ if(gc) {
+ mob_db[class].max_hp+=2000*gc->defense;
+ md->hp=mob_db[class].max_hp;
+ }
+ } // end addition [Valaris]
+
+
+ }
+ return (amount>0)?md->bl.id:0;
+}
+/*==========================================
+ * The MOB appearance for one time (& area specification for scripts)
+ *------------------------------------------
+ */
+int mob_once_spawn_area(struct map_session_data *sd,char *mapname,
+ int x0,int y0,int x1,int y1,
+ const char *mobname,int class,int amount,const char *event)
+{
+ int x,y,i,c,max,lx=-1,ly=-1,id=0;
+ int m;
+
+ if(strcmp(mapname,"this")==0)
+ m=sd->bl.m;
+ else
+ m=map_mapname2mapid(mapname);
+
+ max=(y1-y0+1)*(x1-x0+1)*3;
+ if(max>1000)max=1000;
+
+ if(m<0 || amount<=0 || (class>=0 && class<=1000) || class>2000) // A summon is stopped if a value is unusual
+ return 0;
+
+ for(i=0;i<amount;i++){
+ int j=0;
+ do{
+ x=rand()%(x1-x0+1)+x0;
+ y=rand()%(y1-y0+1)+y0;
+ }while( ( (c=map_getcell(m,x,y))==1 || c==5)&& (++j)<max );
+ if(j>=max){
+ if(lx>=0){ // Since reference went wrong, the place which boiled before is used.
+ x=lx;
+ y=ly;
+ }else
+ return 0; // Since reference of the place which boils first went wrong, it stops.
+ }
+ id=mob_once_spawn(sd,mapname,x,y,mobname,class,1,event);
+ lx=x;
+ ly=y;
+ }
+ return id;
+}
+
+/*==========================================
+ * Summoning Guardians [Valaris]
+ *------------------------------------------
+ */
+int mob_spawn_guardian(struct map_session_data *sd,char *mapname,
+ int x,int y,const char *mobname,int class,int amount,const char *event,int guardian)
+{
+ struct mob_data *md=NULL;
+ int m,count=1,lv=255;
+
+ if( sd )
+ lv=sd->status.base_level;
+
+ if( sd && strcmp(mapname,"this")==0)
+ m=sd->bl.m;
+ else
+ m=map_mapname2mapid(mapname);
+
+ if(m<0 || amount<=0 || (class>=0 && class<=1000) || class>2000) // 値が異常なら召喚を止める
+ return 0;
+
+ if(class<0)
+ return 0;
+
+ if(sd){
+ if(x<=0) x=sd->bl.x;
+ if(y<=0) y=sd->bl.y;
+ }
+
+ else if(x<=0 || y<=0)
+ printf("mob_spawn_guardian: ??\n");
+
+
+ for(count=0;count<amount;count++){
+ struct guild_castle *gc;
+ md=calloc(sizeof(struct mob_data), 1);
+ if(md==NULL){
+ printf("mob_spawn_guardian: out of memory !\n");
+ exit(1);
+ }
+ memset(md, '\0', sizeof *md);
+
+
+
+ mob_spawn_dataset(md,mobname,class);
+ md->bl.m=m;
+ md->bl.x=x;
+ md->bl.y=y;
+ md->m =m;
+ md->x0=x;
+ md->y0=y;
+ md->xs=0;
+ md->ys=0;
+ md->spawndelay1=-1; // Only once is a flag.
+ md->spawndelay2=-1; // Only once is a flag.
+
+ memcpy(md->npc_event,event,sizeof(md->npc_event));
+
+ md->bl.type=BL_MOB;
+ map_addiddb(&md->bl);
+ mob_spawn(md->bl.id);
+
+ gc=guild_mapname2gc(map[md->bl.m].name);
+ if(gc) {
+ mob_db[class].max_hp+=2000*gc->defense;
+ if(guardian==0) { md->hp=gc->Ghp0; gc->GID0=md->bl.id; }
+ if(guardian==1) { md->hp=gc->Ghp1; gc->GID1=md->bl.id; }
+ if(guardian==2) { md->hp=gc->Ghp2; gc->GID2=md->bl.id; }
+ if(guardian==3) { md->hp=gc->Ghp3; gc->GID3=md->bl.id; }
+ if(guardian==4) { md->hp=gc->Ghp4; gc->GID4=md->bl.id; }
+ if(guardian==5) { md->hp=gc->Ghp5; gc->GID5=md->bl.id; }
+ if(guardian==6) { md->hp=gc->Ghp6; gc->GID6=md->bl.id; }
+ if(guardian==7) { md->hp=gc->Ghp7; gc->GID7=md->bl.id; }
+
+ }
+ }
+
+ return (amount>0)?md->bl.id:0;
+}
+
+/*==========================================
+ * The disregard ID is added to mob.
+ *------------------------------------------
+ */
+int mob_exclusion_add(struct mob_data *md,int type,int id)
+{
+ nullpo_retr(0, md);
+
+ if(type==1)
+ md->exclusion_src=id;
+ if(type==2)
+ md->exclusion_party=id;
+ if(type==3)
+ md->exclusion_guild=id;
+
+ return 0;
+}
+
+/*==========================================
+ * The disregard ID of mob is checked. (TAGE?)
+ *------------------------------------------
+ */
+int mob_exclusion_check(struct mob_data *md,struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+ nullpo_retr(0, md);
+
+ if(sd->bl.type==BL_PC){
+ if(md->exclusion_src && md->exclusion_src==sd->bl.id)
+ return 1;
+ if(md->exclusion_party && md->exclusion_party==sd->status.party_id)
+ return 2;
+ if(md->exclusion_guild && md->exclusion_guild==sd->status.guild_id)
+ return 3;
+ }
+ return 0;
+}
+
+/*==========================================
+ * Appearance income of mob
+ *------------------------------------------
+ */
+int mob_get_viewclass(int class)
+{
+ return mob_db[class].view_class;
+}
+int mob_get_sex(int class)
+{
+ return mob_db[class].sex;
+}
+short mob_get_hair(int class)
+{
+ return mob_db[class].hair;
+}
+short mob_get_hair_color(int class)
+{
+ return mob_db[class].hair_color;
+}
+short mob_get_weapon(int class)
+{
+ return mob_db[class].weapon;
+}
+short mob_get_shield(int class)
+{
+ return mob_db[class].shield;
+}
+short mob_get_head_top(int class)
+{
+ return mob_db[class].head_top;
+}
+short mob_get_head_mid(int class)
+{
+ return mob_db[class].head_mid;
+}
+short mob_get_head_buttom(int class)
+{
+ return mob_db[class].head_buttom;
+}
+short mob_get_clothes_color(int class) // Add for player monster dye - Valaris
+{
+ return mob_db[class].clothes_color; // End
+}
+int mob_get_equip(int class) // mob equip [Valaris]
+{
+ return mob_db[class].equip;
+}
+/*==========================================
+ * Is MOB in the state in which the present movement is possible or not?
+ *------------------------------------------
+ */
+int mob_can_move(struct mob_data *md)
+{
+ nullpo_retr(0, md);
+
+ if(md->canmove_tick > gettick() || (md->opt1 > 0 && md->opt1 != 6) || md->option&2)
+ return 0;
+ // アンクル中で動けないとか
+ if( md->sc_data[SC_ANKLE].timer != -1 || //アンクルスネア
+ md->sc_data[SC_AUTOCOUNTER].timer != -1 || //オートカウンター
+ md->sc_data[SC_BLADESTOP].timer != -1 || //白刃取り
+ md->sc_data[SC_SPIDERWEB].timer != -1 //スパイダーウェッブ
+ )
+ return 0;
+
+ return 1;
+}
+
+/*==========================================
+ * Time calculation concerning one step next to mob
+ *------------------------------------------
+ */
+static int calc_next_walk_step(struct mob_data *md)
+{
+ nullpo_retr(0, md);
+
+ if(md->walkpath.path_pos>=md->walkpath.path_len)
+ return -1;
+ if(md->walkpath.path[md->walkpath.path_pos]&1)
+ return battle_get_speed(&md->bl)*14/10;
+ return battle_get_speed(&md->bl);
+}
+
+static int mob_walktoxy_sub(struct mob_data *md);
+
+/*==========================================
+ * Mob Walk processing
+ *------------------------------------------
+ */
+static int mob_walk(struct mob_data *md,unsigned int tick,int data)
+{
+ int moveblock;
+ int i,ctype;
+ static int dirx[8]={0,-1,-1,-1,0,1,1,1};
+ static int diry[8]={1,1,0,-1,-1,-1,0,1};
+ int x,y,dx,dy;
+
+ nullpo_retr(0, md);
+
+ md->state.state=MS_IDLE;
+ if(md->walkpath.path_pos>=md->walkpath.path_len || md->walkpath.path_pos!=data)
+ return 0;
+
+ md->walkpath.path_half ^= 1;
+ if(md->walkpath.path_half==0){
+ md->walkpath.path_pos++;
+ if(md->state.change_walk_target){
+ mob_walktoxy_sub(md);
+ return 0;
+ }
+ }
+ else {
+ if(md->walkpath.path[md->walkpath.path_pos]>=8)
+ return 1;
+
+ x = md->bl.x;
+ y = md->bl.y;
+ ctype = map_getcell(md->bl.m,x,y);
+ if(ctype == 1 || ctype == 5) {
+ mob_stop_walking(md,1);
+ return 0;
+ }
+ md->dir=md->walkpath.path[md->walkpath.path_pos];
+ dx = dirx[md->dir];
+ dy = diry[md->dir];
+
+ ctype = map_getcell(md->bl.m,x+dx,y+dy);
+ if(ctype == 1 || ctype == 5) {
+ mob_walktoxy_sub(md);
+ return 0;
+ }
+
+ moveblock = ( x/BLOCK_SIZE != (x+dx)/BLOCK_SIZE || y/BLOCK_SIZE != (y+dy)/BLOCK_SIZE);
+
+ md->state.state=MS_WALK;
+ map_foreachinmovearea(clif_moboutsight,md->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,BL_PC,md);
+
+ x += dx;
+ y += dy;
+ if(md->min_chase>13)
+ md->min_chase--;
+
+ if(moveblock) map_delblock(&md->bl);
+ md->bl.x = x;
+ md->bl.y = y;
+ if(moveblock) map_addblock(&md->bl);
+
+ map_foreachinmovearea(clif_mobinsight,md->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,-dx,-dy,BL_PC,md);
+ md->state.state=MS_IDLE;
+
+ if(md->option&4)
+ skill_check_cloaking(&md->bl);
+
+ skill_unit_move(&md->bl,tick,1); // Inspection of a skill unit
+ }
+ if((i=calc_next_walk_step(md))>0){
+ i = i>>1;
+ if(i < 1 && md->walkpath.path_half == 0)
+ i = 1;
+ md->timer=add_timer(tick+i,mob_timer,md->bl.id,md->walkpath.path_pos);
+ md->state.state=MS_WALK;
+
+ if(md->walkpath.path_pos>=md->walkpath.path_len)
+ clif_fixmobpos(md); // When mob stops, retransmission current of a position.
+ }
+ return 0;
+}
+
+/*==========================================
+ * Attack processing of mob
+ *------------------------------------------
+ */
+static int mob_attack(struct mob_data *md,unsigned int tick,int data)
+{
+ struct block_list *tbl=NULL;
+ struct map_session_data *tsd=NULL;
+ struct mob_data *tmd=NULL;
+
+ int mode,race,range;
+
+ nullpo_retr(0, md);
+
+ md->min_chase=13;
+ md->state.state=MS_IDLE;
+ md->state.skillstate=MSS_IDLE;
+
+ if( md->skilltimer!=-1 ) // スキル使用中
+ return 0;
+
+ if(md->opt1>0 || md->option&2)
+ return 0;
+
+ if(md->sc_data[SC_AUTOCOUNTER].timer != -1)
+ return 0;
+
+ if(md->sc_data[SC_BLADESTOP].timer != -1)
+ return 0;
+
+ if((tbl=map_id2bl(md->target_id))==NULL){
+ md->target_id=0;
+ md->state.targettype = NONE_ATTACKABLE;
+ return 0;
+ }
+
+ if(tbl->type==BL_PC)
+ tsd=(struct map_session_data *)tbl;
+ else if(tbl->type==BL_MOB)
+ tmd=(struct mob_data *)tbl;
+ else
+ return 0;
+
+ if(tsd){
+ if( pc_isdead(tsd) || tsd->invincible_timer != -1 || pc_isinvisible(tsd) || md->bl.m != tbl->m || tbl->prev == NULL || distance(md->bl.x,md->bl.y,tbl->x,tbl->y)>=13 ){
+ md->target_id=0;
+ md->state.targettype = NONE_ATTACKABLE;
+ return 0;
+ }
+ }
+ if(tmd){
+ if(md->bl.m != tbl->m || tbl->prev == NULL || distance(md->bl.x,md->bl.y,tbl->x,tbl->y)>=13){
+ md->target_id=0;
+ md->state.targettype = NONE_ATTACKABLE;
+ return 0;
+ }
+ }
+
+
+ if(!md->mode)
+ mode=mob_db[md->class].mode;
+ else
+ mode=md->mode;
+
+ race=mob_db[md->class].race;
+ if(!(mode&0x80)){
+ md->target_id=0;
+ md->state.targettype = NONE_ATTACKABLE;
+ return 0;
+ }
+ if(tsd && !(mode&0x20) && (tsd->sc_data[SC_TRICKDEAD].timer != -1 ||
+ ((pc_ishiding(tsd) || tsd->state.gangsterparadise) && race!=4 && race!=6) ) ) {
+ md->target_id=0;
+ md->state.targettype = NONE_ATTACKABLE;
+ return 0;
+ }
+
+ range = mob_db[md->class].range;
+ if(mode&1)
+ range++;
+ if(distance(md->bl.x,md->bl.y,tbl->x,tbl->y) > range)
+ return 0;
+ if(battle_config.monster_attack_direction_change)
+ md->dir=map_calc_dir(&md->bl, tbl->x,tbl->y ); // 向き設定
+
+ //clif_fixmobpos(md);
+
+ md->state.skillstate=MSS_ATTACK;
+ if( mobskill_use(md,tick,-2) ) // スキル使用
+ return 0;
+
+ md->target_lv = battle_weapon_attack(&md->bl,tbl,tick,0);
+
+ if(!(battle_config.monster_cloak_check_type&2) && md->sc_data[SC_CLOAKING].timer != -1)
+ skill_status_change_end(&md->bl,SC_CLOAKING,-1);
+
+ md->attackabletime = tick + battle_get_adelay(&md->bl);
+
+ md->timer=add_timer(md->attackabletime,mob_timer,md->bl.id,0);
+ md->state.state=MS_ATTACK;
+
+ return 0;
+}
+
+
+/*==========================================
+ * The attack of PC which is attacking id is stopped.
+ * The callback function of clif_foreachclient
+ *------------------------------------------
+ */
+int mob_stopattacked(struct map_session_data *sd,va_list ap)
+{
+ int id;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, ap);
+
+ id=va_arg(ap,int);
+ if(sd->attacktarget==id)
+ pc_stopattack(sd);
+ return 0;
+}
+/*==========================================
+ * The timer in which the mob's states changes
+ *------------------------------------------
+ */
+int mob_changestate(struct mob_data *md,int state,int type)
+{
+ unsigned int tick;
+ int i;
+
+ nullpo_retr(0, md);
+
+ if(md->timer != -1)
+ delete_timer(md->timer,mob_timer);
+ md->timer=-1;
+ md->state.state=state;
+
+ switch(state){
+ case MS_WALK:
+ if((i=calc_next_walk_step(md))>0){
+ i = i>>2;
+ md->timer=add_timer(gettick()+i,mob_timer,md->bl.id,0);
+ }
+ else
+ md->state.state=MS_IDLE;
+ break;
+ case MS_ATTACK:
+ tick = gettick();
+ i=DIFF_TICK(md->attackabletime,tick);
+ if(i>0 && i<2000)
+ md->timer=add_timer(md->attackabletime,mob_timer,md->bl.id,0);
+ else if(type) {
+ md->attackabletime = tick + battle_get_amotion(&md->bl);
+ md->timer=add_timer(md->attackabletime,mob_timer,md->bl.id,0);
+ }
+ else {
+ md->attackabletime = tick + 1;
+ md->timer=add_timer(md->attackabletime,mob_timer,md->bl.id,0);
+ }
+ break;
+ case MS_DELAY:
+ md->timer=add_timer(gettick()+type,mob_timer,md->bl.id,0);
+ break;
+ case MS_DEAD:
+ skill_castcancel(&md->bl,0);
+// mobskill_deltimer(md);
+ md->state.skillstate=MSS_DEAD;
+ md->last_deadtime=gettick();
+ // Since it died, all aggressors' attack to this mob is stopped.
+ clif_foreachclient(mob_stopattacked,md->bl.id);
+ skill_unit_out_all(&md->bl,gettick(),1);
+ skill_status_change_clear(&md->bl,2); // The abnormalities in status are canceled.
+ skill_clear_unitgroup(&md->bl); // All skill unit groups are deleted.
+ skill_cleartimerskill(&md->bl);
+ if(md->deletetimer!=-1)
+ delete_timer(md->deletetimer,mob_timer_delete);
+ md->deletetimer=-1;
+ md->hp=md->target_id=md->attacked_id=0;
+ md->state.targettype = NONE_ATTACKABLE;
+ break;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * timer processing of mob (timer function)
+ * It branches to a walk and an attack.
+ *------------------------------------------
+ */
+static int mob_timer(int tid,unsigned int tick,int id,int data)
+{
+ struct mob_data *md;
+ struct block_list *bl;
+
+ if( (bl=map_id2bl(id)) == NULL ){ //攻撃してきた敵がもういないのは正常のようだ
+ return 1;
+ }
+
+ if(!bl || !bl->type || bl->type!=BL_MOB)
+ return 1;
+
+ nullpo_retr(1, md=(struct mob_data*)bl);
+
+ if(!md->bl.type || md->bl.type!=BL_MOB)
+ return 1;
+
+ if(md->timer != tid){
+ if(battle_config.error_log==1)
+ printf("mob_timer %d != %d\n",md->timer,tid);
+ return 0;
+ }
+ md->timer=-1;
+ if(md->bl.prev == NULL || md->state.state == MS_DEAD)
+ return 1;
+
+ map_freeblock_lock();
+ switch(md->state.state){
+ case MS_WALK:
+ mob_walk(md,tick,data);
+ break;
+ case MS_ATTACK:
+ mob_attack(md,tick,data);
+ break;
+ case MS_DELAY:
+ mob_changestate(md,MS_IDLE,0);
+ break;
+ default:
+ if(battle_config.error_log==1)
+ printf("mob_timer : %d ?\n",md->state.state);
+ break;
+ }
+ map_freeblock_unlock();
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static int mob_walktoxy_sub(struct mob_data *md)
+{
+ struct walkpath_data wpd;
+
+ nullpo_retr(0, md);
+
+ if(path_search(&wpd,md->bl.m,md->bl.x,md->bl.y,md->to_x,md->to_y,md->state.walk_easy))
+ return 1;
+ memcpy(&md->walkpath,&wpd,sizeof(wpd));
+
+ md->state.change_walk_target=0;
+ mob_changestate(md,MS_WALK,0);
+ clif_movemob(md);
+
+ return 0;
+}
+
+/*==========================================
+ * mob move start
+ *------------------------------------------
+ */
+int mob_walktoxy(struct mob_data *md,int x,int y,int easy)
+{
+ struct walkpath_data wpd;
+
+ nullpo_retr(0, md);
+
+ if(md->state.state == MS_WALK && path_search(&wpd,md->bl.m,md->bl.x,md->bl.y,x,y,easy) )
+ return 1;
+
+ md->state.walk_easy = easy;
+ md->to_x=x;
+ md->to_y=y;
+ if(md->state.state == MS_WALK) {
+ md->state.change_walk_target=1;
+ } else {
+ return mob_walktoxy_sub(md);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * mob spawn with delay (timer function)
+ *------------------------------------------
+ */
+static int mob_delayspawn(int tid,unsigned int tick,int m,int n)
+{
+ mob_spawn(m);
+ return 0;
+}
+
+/*==========================================
+ * spawn timing calculation
+ *------------------------------------------
+ */
+int mob_setdelayspawn(int id)
+{
+ unsigned int spawntime,spawntime1,spawntime2,spawntime3;
+ struct mob_data *md;
+ struct block_list *bl;
+
+ if((bl=map_id2bl(id)) == NULL)
+ return -1;
+
+ if(!bl || !bl->type || bl->type!=BL_MOB)
+ return -1;
+
+ nullpo_retr(-1, md=(struct mob_data*)bl);
+
+ if(!md || md->bl.type!=BL_MOB)
+ return -1;
+
+ // Processing of MOB which is not revitalized
+ if(md->spawndelay1==-1 && md->spawndelay2==-1 && md->n==0){
+ map_deliddb(&md->bl);
+ if(md->lootitem) {
+ map_freeblock(md->lootitem);
+ md->lootitem=NULL;
+ }
+ map_freeblock(md); // Instead of [ of free ]
+ return 0;
+ }
+
+ spawntime1=md->last_spawntime+md->spawndelay1;
+ spawntime2=md->last_deadtime+md->spawndelay2;
+ spawntime3=gettick()+5000;
+ // spawntime = max(spawntime1,spawntime2,spawntime3);
+ if(DIFF_TICK(spawntime1,spawntime2)>0){
+ spawntime=spawntime1;
+ } else {
+ spawntime=spawntime2;
+ }
+ if(DIFF_TICK(spawntime3,spawntime)>0){
+ spawntime=spawntime3;
+ }
+
+ add_timer(spawntime,mob_delayspawn,id,0);
+ return 0;
+}
+
+/*==========================================
+ * Mob spawning. Initialization is also variously here.
+ *------------------------------------------
+ */
+int mob_spawn(int id)
+{
+ int x=0,y=0,i=0,c;
+ unsigned int tick = gettick();
+ struct mob_data *md;
+ struct block_list *bl;
+
+ nullpo_retr(-1, bl=map_id2bl(id));
+
+ if(!bl || !bl->type || bl->type!=BL_MOB)
+ return -1;
+
+ nullpo_retr(-1, md=(struct mob_data*)bl);
+
+ if(!md || !md->bl.type || md->bl.type!=BL_MOB)
+ return -1;
+
+ md->last_spawntime=tick;
+ if( md->bl.prev!=NULL ){
+// clif_clearchar_area(&md->bl,3);
+ skill_unit_out_all(&md->bl,gettick(),1);
+ map_delblock(&md->bl);
+ }
+ else
+ md->class = md->base_class;
+
+ md->bl.m =md->m;
+ do {
+ if(md->x0==0 && md->y0==0){
+ x=rand()%(map[md->bl.m].xs-2)+1;
+ y=rand()%(map[md->bl.m].ys-2)+1;
+ } else {
+ x=md->x0+rand()%(md->xs+1)-md->xs/2;
+ y=md->y0+rand()%(md->ys+1)-md->ys/2;
+ }
+ i++;
+ } while(((c=map_getcell(md->bl.m,x,y))==1 || c==5) && i<50);
+
+ if(i>=50){
+// if(battle_config.error_log==1)
+// printf("MOB spawn error %d @ %s\n",id,map[md->bl.m].name);
+ add_timer(tick+5000,mob_delayspawn,id,0);
+ return 1;
+ }
+
+ md->to_x=md->bl.x=x;
+ md->to_y=md->bl.y=y;
+ md->dir=0;
+
+ map_addblock(&md->bl);
+
+ memset(&md->state,0,sizeof(md->state));
+ md->attacked_id = 0;
+ md->target_id = 0;
+ md->move_fail_count = 0;
+
+ if(!md->speed)
+ md->speed = mob_db[md->class].speed;
+ md->def_ele = mob_db[md->class].element;
+ md->master_id=0;
+ md->master_dist=0;
+
+ md->state.state = MS_IDLE;
+ md->state.skillstate = MSS_IDLE;
+ md->timer = -1;
+ md->last_thinktime = tick;
+ md->next_walktime = tick+rand()%50+5000;
+ md->attackabletime = tick;
+ md->canmove_tick = tick;
+
+ md->sg_count=0;
+ md->deletetimer=-1;
+
+ md->skilltimer=-1;
+ for(i=0,c=tick-1000*3600*10;i<MAX_MOBSKILL;i++)
+ md->skilldelay[i] = c;
+ md->skillid=0;
+ md->skilllv=0;
+
+ memset(md->dmglog,0,sizeof(md->dmglog));
+ if(md->lootitem)
+ memset(md->lootitem,0,sizeof(md->lootitem));
+ md->lootitem_count = 0;
+
+ for(i=0;i<MAX_MOBSKILLTIMERSKILL;i++)
+ md->skilltimerskill[i].timer = -1;
+
+ for(i=0;i<MAX_STATUSCHANGE;i++) {
+ md->sc_data[i].timer=-1;
+ md->sc_data[i].val1 = md->sc_data[i].val2 = md->sc_data[i].val3 = md->sc_data[i].val4 =0;
+ }
+ md->sc_count=0;
+ md->opt1=md->opt2=md->opt3=md->option=0;
+
+ memset(md->skillunit,0,sizeof(md->skillunit));
+ memset(md->skillunittick,0,sizeof(md->skillunittick));
+
+ md->hp = battle_get_max_hp(&md->bl);
+ if(md->hp<=0){
+ mob_makedummymobdb(md->class);
+ md->hp = battle_get_max_hp(&md->bl);
+ }
+
+ clif_spawnmob(md);
+
+ return 0;
+}
+
+/*==========================================
+ * Distance calculation between two points
+ *------------------------------------------
+ */
+static int distance(int x0,int y0,int x1,int y1)
+{
+ int dx,dy;
+
+ dx=abs(x0-x1);
+ dy=abs(y0-y1);
+ return dx>dy ? dx : dy;
+}
+
+/*==========================================
+ * The stop of MOB's attack
+ *------------------------------------------
+ */
+int mob_stopattack(struct mob_data *md)
+{
+ md->target_id=0;
+ md->state.targettype = NONE_ATTACKABLE;
+ md->attacked_id=0;
+ return 0;
+}
+/*==========================================
+ * The stop of MOB's walking
+ *------------------------------------------
+ */
+int mob_stop_walking(struct mob_data *md,int type)
+{
+ nullpo_retr(0, md);
+
+
+ if(md->state.state == MS_WALK || md->state.state == MS_IDLE) {
+ int dx=0,dy=0;
+
+ md->walkpath.path_len=0;
+ if(type&4){
+ dx=md->to_x-md->bl.x;
+ if(dx<0)
+ dx=-1;
+ else if(dx>0)
+ dx=1;
+ dy=md->to_y-md->bl.y;
+ if(dy<0)
+ dy=-1;
+ else if(dy>0)
+ dy=1;
+ }
+ md->to_x=md->bl.x+dx;
+ md->to_y=md->bl.y+dy;
+ if(dx!=0 || dy!=0){
+ mob_walktoxy_sub(md);
+ return 0;
+ }
+ mob_changestate(md,MS_IDLE,0);
+ }
+ if(type&0x01)
+ clif_fixmobpos(md);
+ if(type&0x02) {
+ int delay=battle_get_dmotion(&md->bl);
+ unsigned int tick = gettick();
+ if(md->canmove_tick < tick)
+ md->canmove_tick = tick + delay;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * Reachability to a Specification ID existence place
+ *------------------------------------------
+ */
+int mob_can_reach(struct mob_data *md,struct block_list *bl,int range)
+{
+ int dx,dy;
+ struct walkpath_data wpd;
+ int i;
+
+ nullpo_retr(0, md);
+ nullpo_retr(0, bl);
+
+ dx=abs(bl->x - md->bl.x);
+ dy=abs(bl->y - md->bl.y);
+
+ //=========== guildcastle guardian no search start===========
+ //when players are the guild castle member not attack them !
+ if(md->class == 1285 || md->class == 1286 || md->class == 1287){
+ struct map_session_data *sd;
+ struct guild *g=NULL;
+ struct guild_castle *gc=guild_mapname2gc(map[bl->m].name);
+
+ if(gc && agit_flag==0) // Guardians will not attack during non-woe time [Valaris]
+ return 0; // end addition [Valaris]
+
+ if(bl && bl->type == BL_PC){
+ if((sd=(struct map_session_data *)bl) == NULL){
+ printf("mob_can_reach nullpo\n");
+ return 0;
+ }
+
+ if(gc && sd && sd->status.guild_id && sd->status.guild_id>0) {
+ g=guild_search(sd->status.guild_id); // don't attack guild members [Valaris]
+ if(g && g->guild_id > 0 && g->guild_id == gc->guild_id)
+ return 0;
+ if(g && gc && guild_isallied(g,gc))
+ return 0;
+
+ }
+ }
+ }
+ //========== guildcastle guardian no search eof==============
+
+ if(bl && bl->type == BL_PC && battle_config.monsters_ignore_gm==1) { // option to have monsters ignore GMs [Valaris]
+ struct map_session_data *sd;
+ if((sd=(struct map_session_data *)bl) != NULL && pc_isGM(sd))
+ return 0;
+ }
+
+ if( md->bl.m != bl->m) // 違うャbプ
+ return 0;
+
+ if( range>0 && range < ((dx>dy)?dx:dy) ) // 遠すぎる
+ return 0;
+
+ if( md->bl.x==bl->x && md->bl.y==bl->y ) // 同じャX
+ return 1;
+
+ // Obstacle judging
+ wpd.path_len=0;
+ wpd.path_pos=0;
+ wpd.path_half=0;
+ if(path_search(&wpd,md->bl.m,md->bl.x,md->bl.y,bl->x,bl->y,0)!=-1)
+ return 1;
+
+ if(bl->type!=BL_PC && bl->type!=BL_MOB)
+ return 0;
+
+ // It judges whether it can adjoin or not.
+ dx=(dx>0)?1:((dx<0)?-1:0);
+ dy=(dy>0)?1:((dy<0)?-1:0);
+ if(path_search(&wpd,md->bl.m,md->bl.x,md->bl.y,bl->x-dx,bl->y-dy,0)!=-1)
+ return 1;
+ for(i=0;i<9;i++){
+ if(path_search(&wpd,md->bl.m,md->bl.x,md->bl.y,bl->x-1+i/3,bl->y-1+i%3,0)!=-1)
+ return 1;
+ }
+ return 0;
+}
+
+/*==========================================
+ * Determination for an attack of a monster
+ *------------------------------------------
+ */
+int mob_target(struct mob_data *md,struct block_list *bl,int dist)
+{
+ struct map_session_data *sd;
+ struct status_change *sc_data;
+ short *option;
+ int mode,race;
+
+ nullpo_retr(0, md);
+ nullpo_retr(0, bl);
+
+ sc_data = battle_get_sc_data(bl);
+ option = battle_get_option(bl);
+ race=mob_db[md->class].race;
+
+ if(!md->mode){
+ mode=mob_db[md->class].mode;
+ }else{
+ mode=md->mode;
+ }
+ if(!(mode&0x80)) {
+ md->target_id = 0;
+ return 0;
+ }
+ // Nothing will be carried out if there is no mind of changing TAGE by TAGE ending.
+ if( (md->target_id > 0 && md->state.targettype == ATTACKABLE) && ( !(mode&0x04) || rand()%100>25) )
+ return 0;
+
+ if(mode&0x20 || // Coercion is exerted if it is MVPMOB.
+ (sc_data && sc_data[SC_TRICKDEAD].timer == -1 &&
+ ( (option && !(*option&0x06) ) || race==4 || race==6) ) ){
+ if(bl->type == BL_PC) {
+ nullpo_retr(0, sd = (struct map_session_data *)bl);
+ if(sd->invincible_timer != -1 || pc_isinvisible(sd))
+ return 0;
+ if(!(mode&0x20) && race!=4 && race!=6 && sd->state.gangsterparadise)
+ return 0;
+ }
+
+ md->target_id=bl->id; // Since there was no disturbance, it locks on to target.
+ if(bl->type == BL_PC || bl->type == BL_MOB)
+ md->state.targettype = ATTACKABLE;
+ else
+ md->state.targettype = NONE_ATTACKABLE;
+ md->min_chase=dist+13;
+ if(md->min_chase>26)
+ md->min_chase=26;
+ }
+ return 0;
+}
+
+/*==========================================
+ * The ?? routine of an active monster
+ *------------------------------------------
+ */
+static int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap)
+{
+ struct map_session_data *tsd=NULL;
+ struct mob_data *smd,*tmd=NULL;
+ int mode,race,dist,*pcc;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, smd=va_arg(ap,struct mob_data *));
+ nullpo_retr(0, pcc=va_arg(ap,int *));
+
+ if(bl->type==BL_PC)
+ tsd=(struct map_session_data *)bl;
+ else if(bl->type==BL_MOB)
+ tmd=(struct mob_data *)bl;
+ else
+ return 0;
+
+ //敵味方判定
+ if(battle_check_target(&smd->bl,bl,BCT_ENEMY)==0)
+ return 0;
+
+ if(!smd->mode)
+ mode=mob_db[smd->class].mode;
+ else
+ mode=smd->mode;
+
+ // アクティブでターゲット射程内にいるなら、ロックする
+ if( mode&0x04 ){
+ race=mob_db[smd->class].race;
+ //対象がPCの場合
+ if(tsd &&
+ !pc_isdead(tsd) &&
+ tsd->bl.m == smd->bl.m &&
+ tsd->invincible_timer == -1 &&
+ !pc_isinvisible(tsd) &&
+ (dist=distance(smd->bl.x,smd->bl.y,tsd->bl.x,tsd->bl.y))<9
+ )
+ {
+ if(mode&0x20 ||
+ (tsd->sc_data[SC_TRICKDEAD].timer == -1 &&
+ ((!pc_ishiding(tsd) && !tsd->state.gangsterparadise) || race==4 || race==6))){ // 妨害がないか判定
+ if( mob_can_reach(smd,bl,12) && // 到達可能性判定
+ rand()%1000<1000/(++(*pcc)) ){ // 範囲内PCで等確率にする
+ smd->target_id=tsd->bl.id;
+ smd->state.targettype = ATTACKABLE;
+ smd->min_chase=13;
+ }
+ }
+ }
+ //対象がMobの場合
+ else if(tmd &&
+ tmd->bl.m == smd->bl.m &&
+ (dist=distance(smd->bl.x,smd->bl.y,tmd->bl.x,tmd->bl.y))<9
+ )
+ {
+ if( mob_can_reach(smd,bl,12) && // 到達可能性判定
+ rand()%1000<1000/(++(*pcc)) ){ // 範囲内で等確率にする
+ smd->target_id=bl->id;
+ smd->state.targettype = ATTACKABLE;
+ smd->min_chase=13;
+ }
+ }
+ }
+ return 0;
+}
+
+/*==========================================
+ * loot monster item search
+ *------------------------------------------
+ */
+static int mob_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap)
+{
+ struct mob_data* md;
+ int mode,dist,*itc;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, md=va_arg(ap,struct mob_data *));
+ nullpo_retr(0, itc=va_arg(ap,int *));
+
+ if(!md->mode){
+ mode=mob_db[md->class].mode;
+ }else{
+ mode=md->mode;
+ }
+
+ if( !md->target_id && mode&0x02){
+ if(!md->lootitem || (battle_config.monster_loot_type == 1 && md->lootitem_count >= LOOTITEM_SIZE) )
+ return 0;
+ if(bl->m == md->bl.m && (dist=distance(md->bl.x,md->bl.y,bl->x,bl->y))<9){
+ if( mob_can_reach(md,bl,12) && // Reachability judging
+ rand()%1000<1000/(++(*itc)) ){ // It is made a probability, such as within the limits PC.
+ md->target_id=bl->id;
+ md->state.targettype = NONE_ATTACKABLE;
+ md->min_chase=13;
+ }
+ }
+ }
+ return 0;
+}
+
+/*==========================================
+ * The ?? routine of a link monster
+ *------------------------------------------
+ */
+static int mob_ai_sub_hard_linksearch(struct block_list *bl,va_list ap)
+{
+ struct mob_data *tmd;
+ struct mob_data* md;
+ struct block_list *target;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, tmd=(struct mob_data *)bl);
+ nullpo_retr(0, md=va_arg(ap,struct mob_data *));
+ nullpo_retr(0, target=va_arg(ap,struct block_list *));
+
+ // same family free in a range at a link monster -- it will be made to lock if MOB is
+/* if( (md->target_id > 0 && md->state.targettype == ATTACKABLE) && mob_db[md->class].mode&0x08){
+ if( tmd->class==md->class && (!tmd->target_id || md->state.targettype == NONE_ATTACKABLE) && tmd->bl.m == md->bl.m){
+ if( mob_can_reach(tmd,target,12) ){ // Reachability judging
+ tmd->target_id=md->target_id;
+ tmd->state.targettype = ATTACKABLE;
+ tmd->min_chase=13;
+ }
+ }
+ }*/
+ if( md->attacked_id > 0 && mob_db[md->class].mode&0x08){
+ if( tmd->class==md->class && tmd->bl.m == md->bl.m && (!tmd->target_id || md->state.targettype == NONE_ATTACKABLE)){
+ if( mob_can_reach(tmd,target,12) ){ // Reachability judging
+ tmd->target_id=md->attacked_id;
+ tmd->state.targettype = ATTACKABLE;
+ tmd->min_chase=13;
+ }
+ }
+ }
+
+ return 0;
+}
+/*==========================================
+ * Processing of slave monsters
+ *------------------------------------------
+ */
+static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick)
+{
+ struct mob_data *mmd=NULL;
+ struct block_list *bl;
+ int mode,race,old_dist;
+
+ nullpo_retr(0, md);
+
+ if((bl=map_id2bl(md->master_id)) != NULL )
+ mmd=(struct mob_data *)bl;
+
+ mode=mob_db[md->class].mode;
+
+ // It is not main monster/leader.
+ if(!mmd || mmd->bl.type!=BL_MOB || mmd->bl.id!=md->master_id)
+ return 0;
+
+ // Since it is in the map on which the master is not, teleport is carried out and it pursues.
+ if( mmd->bl.m != md->bl.m ){
+ mob_warp(md,mmd->bl.m,mmd->bl.x,mmd->bl.y,3);
+ md->state.master_check = 1;
+ return 0;
+ }
+
+ // Distance with between slave and master is measured.
+ old_dist=md->master_dist;
+ md->master_dist=distance(md->bl.x,md->bl.y,mmd->bl.x,mmd->bl.y);
+
+ // Since the master was in near immediately before, teleport is carried out and it pursues.
+ if( old_dist<10 && md->master_dist>18){
+ mob_warp(md,-1,mmd->bl.x,mmd->bl.y,3);
+ md->state.master_check = 1;
+ return 0;
+ }
+
+ // Although there is the master, since it is somewhat far, it approaches.
+ if((!md->target_id || md->state.targettype == NONE_ATTACKABLE) && mob_can_move(md) &&
+ (md->walkpath.path_pos>=md->walkpath.path_len || md->walkpath.path_len==0) && md->master_dist<15){
+ int i=0,dx,dy,ret;
+ if(md->master_dist>4) {
+ do {
+ if(i<=5){
+ dx=mmd->bl.x - md->bl.x;
+ dy=mmd->bl.y - md->bl.y;
+ if(dx<0) dx+=(rand()%( (dx<-3)?3:-dx )+1);
+ else if(dx>0) dx-=(rand()%( (dx>3)?3:dx )+1);
+ if(dy<0) dy+=(rand()%( (dy<-3)?3:-dy )+1);
+ else if(dy>0) dy-=(rand()%( (dy>3)?3:dy )+1);
+ }else{
+ dx=mmd->bl.x - md->bl.x + rand()%7 - 3;
+ dy=mmd->bl.y - md->bl.y + rand()%7 - 3;
+ }
+
+ ret=mob_walktoxy(md,md->bl.x+dx,md->bl.y+dy,0);
+ i++;
+ } while(ret && i<10);
+ }
+ else {
+ do {
+ dx = rand()%9 - 5;
+ dy = rand()%9 - 5;
+ if( dx == 0 && dy == 0) {
+ dx = (rand()%1)? 1:-1;
+ dy = (rand()%1)? 1:-1;
+ }
+ dx += mmd->bl.x;
+ dy += mmd->bl.y;
+
+ ret=mob_walktoxy(md,mmd->bl.x+dx,mmd->bl.y+dy,0);
+ i++;
+ } while(ret && i<10);
+ }
+
+ md->next_walktime=tick+500;
+ md->state.master_check = 1;
+ }
+
+ // There is the master, the master locks a target and he does not lock.
+ if( (mmd->target_id>0 && mmd->state.targettype == ATTACKABLE) && (!md->target_id || md->state.targettype == NONE_ATTACKABLE) ){
+ struct map_session_data *sd=map_id2sd(mmd->target_id);
+ if(sd!=NULL && !pc_isdead(sd) && sd->invincible_timer == -1 && !pc_isinvisible(sd)){
+
+ race=mob_db[md->class].race;
+ if(mode&0x20 ||
+ (sd->sc_data[SC_TRICKDEAD].timer == -1 &&
+ ( (!pc_ishiding(sd) && !sd->state.gangsterparadise) || race==4 || race==6) ) ){ // 妨害がないか判定
+
+ md->target_id=sd->bl.id;
+ md->state.targettype = ATTACKABLE;
+ md->min_chase=5+distance(md->bl.x,md->bl.y,sd->bl.x,sd->bl.y);
+ md->state.master_check = 1;
+ }
+ }
+ }
+
+ // There is the master, the master locks a target and he does not lock.
+/* if( (md->target_id>0 && mmd->state.targettype == ATTACKABLE) && (!mmd->target_id || mmd->state.targettype == NONE_ATTACKABLE) ){
+ struct map_session_data *sd=map_id2sd(md->target_id);
+ if(sd!=NULL && !pc_isdead(sd) && sd->invincible_timer == -1 && !pc_isinvisible(sd)){
+
+ race=mob_db[mmd->class].race;
+ if(mode&0x20 ||
+ (sd->sc_data[SC_TRICKDEAD].timer == -1 &&
+ (!(sd->status.option&0x06) || race==4 || race==6)
+ ) ){ // It judges whether there is any disturbance.
+
+ mmd->target_id=sd->bl.id;
+ mmd->state.targettype = ATTACKABLE;
+ mmd->min_chase=5+distance(mmd->bl.x,mmd->bl.y,sd->bl.x,sd->bl.y);
+ }
+ }
+ }*/
+
+ return 0;
+}
+
+/*==========================================
+ * A lock of target is stopped and mob moves to a standby state.
+ *------------------------------------------
+ */
+static int mob_unlocktarget(struct mob_data *md,int tick)
+{
+ nullpo_retr(0, md);
+
+ md->target_id=0;
+ md->state.targettype = NONE_ATTACKABLE;
+ md->state.skillstate=MSS_IDLE;
+ md->next_walktime=tick+rand()%3000+3000;
+ return 0;
+}
+/*==========================================
+ * Random walk
+ *------------------------------------------
+ */
+static int mob_randomwalk(struct mob_data *md,int tick)
+{
+ const int retrycount=20;
+ int speed;
+
+ nullpo_retr(0, md);
+
+ speed=battle_get_speed(&md->bl);
+ if(DIFF_TICK(md->next_walktime,tick)<0){
+ int i,x,y,c,d=12-md->move_fail_count;
+ if(d<5) d=5;
+ for(i=0;i<retrycount;i++){ // Search of a movable place
+ int r=rand();
+ x=md->bl.x+r%(d*2+1)-d;
+ y=md->bl.y+r/(d*2+1)%(d*2+1)-d;
+ if((c=map_getcell(md->bl.m,x,y))!=1 && c!=5 && mob_walktoxy(md,x,y,1)==0){
+ md->move_fail_count=0;
+ break;
+ }
+ if(i+1>=retrycount){
+ md->move_fail_count++;
+ if(md->move_fail_count>1000){
+ if(battle_config.error_log==1)
+ printf("MOB cant move. random spawn %d, class = %d\n",md->bl.id,md->class);
+ md->move_fail_count=0;
+ mob_spawn(md->bl.id);
+ }
+ }
+ }
+ for(i=c=0;i<md->walkpath.path_len;i++){ // The next walk start time is calculated.
+ if(md->walkpath.path[i]&1)
+ c+=speed*14/10;
+ else
+ c+=speed;
+ }
+ md->next_walktime = tick+rand()%3000+3000+c;
+ md->state.skillstate=MSS_WALK;
+ return 1;
+ }
+ return 0;
+}
+
+/*==========================================
+ * AI of MOB whose is near a Player
+ *------------------------------------------
+ */
+static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
+{
+ struct mob_data *md,*tmd=NULL;
+ struct map_session_data *tsd=NULL;
+ struct block_list *tbl=NULL;
+ struct flooritem_data *fitem;
+ unsigned int tick;
+ int i,dx,dy,ret,dist;
+ int attack_type=0;
+ int mode,race;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, md=(struct mob_data*)bl);
+
+ tick=va_arg(ap,unsigned int);
+
+
+ if(DIFF_TICK(tick,md->last_thinktime)<MIN_MOBTHINKTIME)
+ return 0;
+ md->last_thinktime=tick;
+
+ if( md->skilltimer!=-1 || md->bl.prev==NULL ){ // Under a skill aria and death
+ if(DIFF_TICK(tick,md->next_walktime)>MIN_MOBTHINKTIME)
+ md->next_walktime=tick;
+ return 0;
+ }
+
+ if(!md->mode)
+ mode=mob_db[md->class].mode;
+ else
+ mode=md->mode;
+
+ race=mob_db[md->class].race;
+
+ // Abnormalities
+ if((md->opt1 > 0 && md->opt1 != 6) || md->state.state==MS_DELAY || md->sc_data[SC_BLADESTOP].timer != -1)
+ return 0;
+
+ if(!(mode&0x80) && md->target_id > 0)
+ md->target_id = 0;
+
+ if(md->attacked_id > 0 && mode&0x08){ // Link monster
+ struct map_session_data *asd=map_id2sd(md->attacked_id);
+ if(asd){
+ if(asd->invincible_timer == -1 && !pc_isinvisible(asd)){
+ map_foreachinarea(mob_ai_sub_hard_linksearch,md->bl.m,
+ md->bl.x-13,md->bl.y-13,
+ md->bl.x+13,md->bl.y+13,
+ BL_MOB,md,&asd->bl);
+ }
+ }
+ }
+
+ // It checks to see it was attacked first (if active, it is target change at 25% of probability).
+ if( mode>0 && md->attacked_id>0 && (!md->target_id || md->state.targettype == NONE_ATTACKABLE
+ || (mode&0x04 && rand()%100<25 ) ) ){
+ struct block_list *abl=map_id2bl(md->attacked_id);
+ struct map_session_data *asd=NULL;
+ if(abl){
+ if(abl->type==BL_PC)
+ asd=(struct map_session_data *)abl;
+ if(asd==NULL || md->bl.m != abl->m || abl->prev == NULL || asd->invincible_timer != -1 || pc_isinvisible(asd) ||
+ (dist=distance(md->bl.x,md->bl.y,abl->x,abl->y))>=32 || battle_check_target(bl,abl,BCT_ENEMY)==0)
+ md->attacked_id=0;
+ else {
+ md->target_id=md->attacked_id; // set target
+ md->state.targettype = ATTACKABLE;
+ attack_type = 1;
+ md->attacked_id=0;
+ md->min_chase=dist+13;
+ if(md->min_chase>26)
+ md->min_chase=26;
+ }
+ }
+ }
+
+ md->state.master_check = 0;
+ // Processing of slave monster
+ if( md->master_id > 0 && md->state.special_mob_ai==0)
+ mob_ai_sub_hard_slavemob(md,tick);
+
+ // アクティヴモンスターの策敵 (?? of a bitter taste TIVU monster)
+ if( (!md->target_id || md->state.targettype == NONE_ATTACKABLE) && mode&0x04 && !md->state.master_check &&
+ battle_config.monster_active_enable==1){
+ i=0;
+ if(md->state.special_mob_ai){
+ map_foreachinarea(mob_ai_sub_hard_activesearch,md->bl.m,
+ md->bl.x-AREA_SIZE*2,md->bl.y-AREA_SIZE*2,
+ md->bl.x+AREA_SIZE*2,md->bl.y+AREA_SIZE*2,
+ 0,md,&i);
+ }else{
+ map_foreachinarea(mob_ai_sub_hard_activesearch,md->bl.m,
+ md->bl.x-AREA_SIZE*2,md->bl.y-AREA_SIZE*2,
+ md->bl.x+AREA_SIZE*2,md->bl.y+AREA_SIZE*2,
+ BL_PC,md,&i);
+ }
+ }
+
+ // The item search of a route monster
+ if( !md->target_id && mode&0x02 && !md->state.master_check){
+ i=0;
+ map_foreachinarea(mob_ai_sub_hard_lootsearch,md->bl.m,
+ md->bl.x-AREA_SIZE*2,md->bl.y-AREA_SIZE*2,
+ md->bl.x+AREA_SIZE*2,md->bl.y+AREA_SIZE*2,
+ BL_ITEM,md,&i);
+ }
+
+ // It will attack, if the candidate for an attack is.
+ if(md->target_id > 0){
+ if((tbl=map_id2bl(md->target_id))){
+ if(tbl->type==BL_PC)
+ tsd=(struct map_session_data *)tbl;
+ else if(tbl->type==BL_MOB)
+ tmd=(struct mob_data *)tbl;
+ if(tsd || tmd) {
+ if(tbl->m != md->bl.m || tbl->prev == NULL || (dist=distance(md->bl.x,md->bl.y,tbl->x,tbl->y))>=md->min_chase)
+ mob_unlocktarget(md,tick); // 別マップか、視界外
+ else if( tsd && !(mode&0x20) && (tsd->sc_data[SC_TRICKDEAD].timer != -1 || ((pc_ishiding(tsd) || tsd->state.gangsterparadise) && race!=4 && race!=6)) )
+ mob_unlocktarget(md,tick); // スキルなどによる策敵妨害
+ else if(!battle_check_range(&md->bl,tbl,mob_db[md->class].range)){
+ // 攻撃範囲外なので移動
+ if(!(mode&1)){ // 移動しないモード
+ mob_unlocktarget(md,tick);
+ return 0;
+ }
+ if( !mob_can_move(md) ) // 動けない状態にある
+ return 0;
+ md->state.skillstate=MSS_CHASE; // 突撃時スキル
+ mobskill_use(md,tick,-1);
+// if(md->timer != -1 && (DIFF_TICK(md->next_walktime,tick)<0 || distance(md->to_x,md->to_y,tsd->bl.x,tsd->bl.y)<2) )
+ if(md->timer != -1 && md->state.state!=MS_ATTACK && (DIFF_TICK(md->next_walktime,tick)<0 || distance(md->to_x,md->to_y,tbl->x,tbl->y)<2) )
+ return 0; // 既に移動中
+ if( !mob_can_reach(md,tbl,(md->min_chase>13)?md->min_chase:13) )
+ mob_unlocktarget(md,tick); // 移動できないのでタゲ解除(IWとか?)
+ else{
+ // 追跡
+ md->next_walktime=tick+500;
+ i=0;
+ do {
+ if(i==0){ // 最初はAEGISと同じ方法で検索
+ dx=tbl->x - md->bl.x;
+ dy=tbl->y - md->bl.y;
+ if(dx<0) dx++;
+ else if(dx>0) dx--;
+ if(dy<0) dy++;
+ else if(dy>0) dy--;
+ }else{ // だめならAthena式(ランダム)
+ dx=tbl->x - md->bl.x + rand()%3 - 1;
+ dy=tbl->y - md->bl.y + rand()%3 - 1;
+ }
+ /* if(path_search(&md->walkpath,md->bl.m,md->bl.x,md->bl.y,md->bl.x+dx,md->bl.y+dy,0)){
+ dx=tsd->bl.x - md->bl.x;
+ dy=tsd->bl.y - md->bl.y;
+ if(dx<0) dx--;
+ else if(dx>0) dx++;
+ if(dy<0) dy--;
+ else if(dy>0) dy++;
+ }*/
+ ret=mob_walktoxy(md,md->bl.x+dx,md->bl.y+dy,0);
+ i++;
+ } while(ret && i<5);
+
+ if(ret){ // 移動不可能な所からの攻撃なら2歩下る
+ if(dx<0) dx=2;
+ else if(dx>0) dx=-2;
+ if(dy<0) dy=2;
+ else if(dy>0) dy=-2;
+ mob_walktoxy(md,md->bl.x+dx,md->bl.y+dy,0);
+ }
+ }
+ } else { // 攻撃射程範囲内
+ md->state.skillstate=MSS_ATTACK;
+ if(md->state.state==MS_WALK)
+ mob_stop_walking(md,1); // 歩行中なら停止
+ if(md->state.state==MS_ATTACK)
+ return 0; // 既に攻撃中
+ mob_changestate(md,MS_ATTACK,attack_type);
+
+/* if(mode&0x08){ // リンクモンスター
+ map_foreachinarea(mob_ai_sub_hard_linksearch,md->bl.m,
+ md->bl.x-13,md->bl.y-13,
+ md->bl.x+13,md->bl.y+13,
+ BL_MOB,md,&tsd->bl);
+ }*/
+ }
+ return 0;
+ }else{ // ルートモンスター処理
+ if(tbl == NULL || tbl->type != BL_ITEM ||tbl->m != md->bl.m ||
+ (dist=distance(md->bl.x,md->bl.y,tbl->x,tbl->y))>=md->min_chase || !md->lootitem){
+ // 遠すぎるかアイテムがなくなった
+ mob_unlocktarget(md,tick);
+ if(md->state.state==MS_WALK)
+ mob_stop_walking(md,1); // 歩行中なら停止
+ }else if(dist){
+ if(!(mode&1)){ // 移動しないモード
+ mob_unlocktarget(md,tick);
+ return 0;
+ }
+ if( !mob_can_move(md) ) // 動けない状態にある
+ return 0;
+ md->state.skillstate=MSS_LOOT; // ルート時スキル使用
+ mobskill_use(md,tick,-1);
+// if(md->timer != -1 && (DIFF_TICK(md->next_walktime,tick)<0 || distance(md->to_x,md->to_y,tbl->x,tbl->y)<2) )
+ if(md->timer != -1 && md->state.state!=MS_ATTACK && (DIFF_TICK(md->next_walktime,tick)<0 || distance(md->to_x,md->to_y,tbl->x,tbl->y) <= 0))
+ return 0; // 既に移動中
+ md->next_walktime=tick+500;
+ dx=tbl->x - md->bl.x;
+ dy=tbl->y - md->bl.y;
+/* if(path_search(&md->walkpath,md->bl.m,md->bl.x,md->bl.y,md->bl.x+dx,md->bl.y+dy,0)){
+ dx=tbl->x - md->bl.x;
+ dy=tbl->y - md->bl.y;
+ }*/
+ ret=mob_walktoxy(md,md->bl.x+dx,md->bl.y+dy,0);
+ if(ret)
+ mob_unlocktarget(md,tick);// 移動できないのでタゲ解除(IWとか?)
+ }else{ // アイテムまでたどり着いた
+ if(md->state.state==MS_ATTACK)
+ return 0; // 攻撃中
+ if(md->state.state==MS_WALK)
+ mob_stop_walking(md,1); // 歩行中なら停止
+ fitem = (struct flooritem_data *)tbl;
+ if(md->lootitem_count < LOOTITEM_SIZE)
+ memcpy(&md->lootitem[md->lootitem_count++],&fitem->item_data,sizeof(md->lootitem[0]));
+ else if(battle_config.monster_loot_type == 1 && md->lootitem_count >= LOOTITEM_SIZE) {
+ mob_unlocktarget(md,tick);
+ return 0;
+ }
+ else {
+ if(md->lootitem[0].card[0] == (short)0xff00)
+ intif_delete_petdata(*((long *)(&md->lootitem[0].card[1])));
+ for(i=0;i<LOOTITEM_SIZE-1;i++)
+ memcpy(&md->lootitem[i],&md->lootitem[i+1],sizeof(md->lootitem[0]));
+ memcpy(&md->lootitem[LOOTITEM_SIZE-1],&fitem->item_data,sizeof(md->lootitem[0]));
+ }
+ map_clearflooritem(tbl->id);
+ mob_unlocktarget(md,tick);
+ }
+ return 0;
+ }
+ }else{
+ mob_unlocktarget(md,tick);
+ if(md->state.state==MS_WALK)
+ mob_stop_walking(md,4); // 歩行中なら停止
+ return 0;
+ }
+ }
+
+ // It is skill use at the time of /standby at the time of a walk.
+ if( mobskill_use(md,tick,-1) )
+ return 0;
+
+ // 歩行処理
+ if( mode&1 && mob_can_move(md) && // 移動可能MOB&動ける状態にある
+ (md->master_id==0 || md->state.special_mob_ai || md->master_dist>10) ){ //取り巻きMOBじゃない
+
+ if( DIFF_TICK(md->next_walktime,tick) > + 7000 &&
+ (md->walkpath.path_len==0 || md->walkpath.path_pos>=md->walkpath.path_len) ){
+ md->next_walktime = tick + 3000*rand()%2000;
+ }
+
+ // Random movement
+ if( mob_randomwalk(md,tick) )
+ return 0;
+ }
+
+ // Since he has finished walking, it stands by.
+ if( md->walkpath.path_len==0 || md->walkpath.path_pos>=md->walkpath.path_len )
+ md->state.skillstate=MSS_IDLE;
+ return 0;
+}
+
+/*==========================================
+ * Serious processing for mob in PC field of view (foreachclient)
+ *------------------------------------------
+ */
+static int mob_ai_sub_foreachclient(struct map_session_data *sd,va_list ap)
+{
+ unsigned int tick;
+ nullpo_retr(0, sd);
+ nullpo_retr(0, ap);
+
+ tick=va_arg(ap,unsigned int);
+ map_foreachinarea(mob_ai_sub_hard,sd->bl.m,
+ sd->bl.x-AREA_SIZE*2,sd->bl.y-AREA_SIZE*2,
+ sd->bl.x+AREA_SIZE*2,sd->bl.y+AREA_SIZE*2,
+ BL_MOB,tick);
+
+ return 0;
+}
+
+/*==========================================
+ * Serious processing for mob in PC field of view (interval timer function)
+ *------------------------------------------
+ */
+static int mob_ai_hard(int tid,unsigned int tick,int id,int data)
+{
+ clif_foreachclient(mob_ai_sub_foreachclient,tick);
+
+ return 0;
+}
+
+/*==========================================
+ * Negligent mode MOB AI (PC is not in near)
+ *------------------------------------------
+ */
+static int mob_ai_sub_lazy(void * key,void * data,va_list app)
+{
+ struct mob_data *md=data;
+ unsigned int tick;
+ va_list ap;
+
+ nullpo_retr(0, md);
+ nullpo_retr(0, app);
+ nullpo_retr(0, ap=va_arg(app,va_list));
+
+ if(md==NULL)
+ return 0;
+
+ if(!md->bl.type || md->bl.type!=BL_MOB)
+ return 0;
+
+ tick=va_arg(ap,unsigned int);
+
+ if(DIFF_TICK(tick,md->last_thinktime)<MIN_MOBTHINKTIME*10)
+ return 0;
+ md->last_thinktime=tick;
+
+ if(md->bl.prev==NULL || md->skilltimer!=-1){
+ if(DIFF_TICK(tick,md->next_walktime)>MIN_MOBTHINKTIME*10)
+ md->next_walktime=tick;
+ return 0;
+ }
+
+ if(DIFF_TICK(md->next_walktime,tick)<0 &&
+ (mob_db[md->class].mode&1) && mob_can_move(md) ){
+
+ if( map[md->bl.m].users>0 ){
+ // Since PC is in the same map, somewhat better negligent processing is carried out.
+
+ // It sometimes moves.
+ if(rand()%1000<MOB_LAZYMOVEPERC)
+ mob_randomwalk(md,tick);
+
+ // MOB which is not not the summons MOB but BOSS, either sometimes reboils.
+ else if( rand()%1000<MOB_LAZYWARPPERC && md->x0<=0 && md->master_id!=0 &&
+ mob_db[md->class].mexp <= 0 && !(mob_db[md->class].mode & 0x20))
+ mob_spawn(md->bl.id);
+
+ }else{
+ // Since PC is not even in the same map, suitable processing is carried out even if it takes.
+
+ // MOB which is not BOSS which is not Summons MOB, either -- a case -- sometimes -- leaping
+ if( rand()%1000<MOB_LAZYWARPPERC && md->x0<=0 && md->master_id!=0 &&
+ mob_db[md->class].mexp <= 0 && !(mob_db[md->class].mode & 0x20))
+ mob_warp(md,-1,-1,-1,-1);
+ }
+
+ md->next_walktime = tick+rand()%10000+5000;
+ }
+ return 0;
+}
+
+/*==========================================
+ * Negligent processing for mob outside PC field of view (interval timer function)
+ *------------------------------------------
+ */
+static int mob_ai_lazy(int tid,unsigned int tick,int id,int data)
+{
+ map_foreachiddb(mob_ai_sub_lazy,tick);
+
+ return 0;
+}
+
+
+/*==========================================
+ * The structure object for item drop with delay
+ * Since it is only two being able to pass [ int ] a timer function
+ * Data is put in and passed to this structure object.
+ *------------------------------------------
+ */
+struct delay_item_drop {
+ int m,x,y;
+ int nameid,amount;
+ struct map_session_data *first_sd,*second_sd,*third_sd;
+};
+
+struct delay_item_drop2 {
+ int m,x,y;
+ struct item item_data;
+ struct map_session_data *first_sd,*second_sd,*third_sd;
+};
+
+/*==========================================
+ * item drop with delay (timer function)
+ *------------------------------------------
+ */
+static int mob_delay_item_drop(int tid,unsigned int tick,int id,int data)
+{
+ struct delay_item_drop *ditem;
+ struct item temp_item;
+ int flag;
+
+ nullpo_retr(0, ditem=(struct delay_item_drop *)id);
+
+ memset(&temp_item,0,sizeof(temp_item));
+ temp_item.nameid = ditem->nameid;
+ temp_item.amount = ditem->amount;
+ temp_item.identify = !itemdb_isequip3(temp_item.nameid);
+
+ if(battle_config.item_auto_get==1){
+ if(ditem->first_sd && (flag = pc_additem(ditem->first_sd,&temp_item,ditem->amount))){
+ clif_additem(ditem->first_sd,0,0,flag);
+ map_addflooritem(&temp_item,1,ditem->m,ditem->x,ditem->y,ditem->first_sd,ditem->second_sd,ditem->third_sd,0);
+ }
+ free(ditem);
+ return 0;
+ }
+
+ map_addflooritem(&temp_item,1,ditem->m,ditem->x,ditem->y,ditem->first_sd,ditem->second_sd,ditem->third_sd,0);
+
+ free(ditem);
+ return 0;
+}
+
+/*==========================================
+ * item drop (timer function)-lootitem with delay
+ *------------------------------------------
+ */
+static int mob_delay_item_drop2(int tid,unsigned int tick,int id,int data)
+{
+ struct delay_item_drop2 *ditem;
+ int flag;
+
+ nullpo_retr(0, ditem=(struct delay_item_drop2 *)id);
+
+ if(battle_config.item_auto_get==1){
+ if(ditem->first_sd && (flag = pc_additem(ditem->first_sd,&ditem->item_data,ditem->item_data.amount))){
+ clif_additem(ditem->first_sd,0,0,flag);
+ map_addflooritem(&ditem->item_data,ditem->item_data.amount,ditem->m,ditem->x,ditem->y,ditem->first_sd,ditem->second_sd,ditem->third_sd,0);
+ }
+ free(ditem);
+ return 0;
+ }
+
+ map_addflooritem(&ditem->item_data,ditem->item_data.amount,ditem->m,ditem->x,ditem->y,ditem->first_sd,ditem->second_sd,ditem->third_sd,0);
+
+ free(ditem);
+ return 0;
+}
+
+/*==========================================
+ * mob data is erased.
+ *------------------------------------------
+ */
+int mob_delete(struct mob_data *md)
+{
+ nullpo_retr(1, md);
+
+ if(md->bl.prev == NULL)
+ return 1;
+ mob_changestate(md,MS_DEAD,0);
+ clif_clearchar_area(&md->bl,1);
+ map_delblock(&md->bl);
+ if(mob_get_viewclass(md->class) <= 1000)
+ clif_clearchar_delay(gettick()+3000,&md->bl,0);
+ mob_deleteslave(md);
+ mob_setdelayspawn(md->bl.id);
+ return 0;
+}
+
+int mob_catch_delete(struct mob_data *md,int type)
+{
+ nullpo_retr(1, md);
+
+ if(md->bl.prev == NULL)
+ return 1;
+ mob_changestate(md,MS_DEAD,0);
+ clif_clearchar_area(&md->bl,type);
+ map_delblock(&md->bl);
+ mob_setdelayspawn(md->bl.id);
+ return 0;
+}
+
+int mob_timer_delete(int tid, unsigned int tick, int id, int data)
+{
+ struct block_list *bl=map_id2bl(id);
+ struct mob_data *md;
+
+ nullpo_retr(0, bl);
+
+ md = (struct mob_data *)bl;
+ mob_catch_delete(md,3);
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int mob_deleteslave_sub(struct block_list *bl,va_list ap)
+{
+ struct mob_data *md;
+ int id;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, md = (struct mob_data *)bl);
+
+ id=va_arg(ap,int);
+ if(md->master_id > 0 && md->master_id == id )
+ mob_damage(NULL,md,md->hp,1);
+ return 0;
+}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int mob_deleteslave(struct mob_data *md)
+{
+ nullpo_retr(0, md);
+
+ map_foreachinarea(mob_deleteslave_sub, md->bl.m,
+ 0,0,map[md->bl.m].xs,map[md->bl.m].ys,
+ BL_MOB,md->bl.id);
+ return 0;
+}
+
+/*==========================================
+ * It is the damage of sd to damage to md.
+ *------------------------------------------
+ */
+int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
+{
+ int i,count,minpos,mindmg;
+ struct map_session_data *sd = NULL,*tmpsd[DAMAGELOG_SIZE];
+ struct {
+ struct party *p;
+ int id,base_exp,job_exp;
+ } pt[DAMAGELOG_SIZE];
+ int pnum=0;
+ int mvp_damage,max_hp;
+ unsigned int tick = gettick();
+ struct map_session_data *mvp_sd = NULL, *second_sd = NULL,*third_sd = NULL;
+ double dmg_rate,tdmg,temp;
+ struct item item;
+ int ret;
+ int drop_rate;
+ int skill,sp;
+
+ nullpo_retr(0, md); //srcはNULLで呼ばれる場合もあるので、他でチェック
+
+ max_hp = battle_get_max_hp(&md->bl);
+
+ if(src && src->type == BL_PC) {
+ sd = (struct map_session_data *)src;
+ mvp_sd = sd;
+ }
+
+// if(battle_config.battle_log)
+// printf("mob_damage %d %d %d\n",md->hp,max_hp,damage);
+ if(md->bl.prev==NULL){
+ if(battle_config.error_log==1)
+ printf("mob_damage : BlockError!!\n");
+ return 0;
+ }
+
+ if(md->state.state==MS_DEAD || md->hp<=0) {
+ if(md->bl.prev != NULL) {
+ mob_changestate(md,MS_DEAD,0);
+ mobskill_use(md,tick,-1); // It is skill at the time of death.
+ clif_clearchar_area(&md->bl,1);
+ map_delblock(&md->bl);
+ mob_setdelayspawn(md->bl.id);
+ }
+ return 0;
+ }
+
+ if(md->sc_data[SC_ENDURE].timer == -1)
+ mob_stop_walking(md,3);
+ if(damage > max_hp>>2)
+ skill_stop_dancing(&md->bl,0);
+
+ if(md->hp > max_hp)
+ md->hp = max_hp;
+
+ // The amount of overkill rounds to hp.
+ if(damage>md->hp)
+ damage=md->hp;
+
+ if(!(type&2)) {
+ if(sd!=NULL){
+ for(i=0,minpos=0,mindmg=0x7fffffff;i<DAMAGELOG_SIZE;i++){
+ if(md->dmglog[i].id==sd->bl.id)
+ break;
+ if(md->dmglog[i].id==0){
+ minpos=i;
+ mindmg=0;
+ }
+ else if(md->dmglog[i].dmg<mindmg){
+ minpos=i;
+ mindmg=md->dmglog[i].dmg;
+ }
+ }
+ if(i<DAMAGELOG_SIZE)
+ md->dmglog[i].dmg+=damage;
+ else {
+ md->dmglog[minpos].id=sd->bl.id;
+ md->dmglog[minpos].dmg=damage;
+ }
+
+ if(md->attacked_id <= 0 && md->state.special_mob_ai==0)
+ md->attacked_id = sd->bl.id;
+ }
+ if(src && src->type == BL_PET && battle_config.pet_attack_exp_to_master==1) {
+ struct pet_data *pd = (struct pet_data *)src;
+ nullpo_retr(0, pd);
+ for(i=0,minpos=0,mindmg=0x7fffffff;i<DAMAGELOG_SIZE;i++){
+ if(md->dmglog[i].id==pd->msd->bl.id)
+ break;
+ if(md->dmglog[i].id==0){
+ minpos=i;
+ mindmg=0;
+ }
+ else if(md->dmglog[i].dmg<mindmg){
+ minpos=i;
+ mindmg=md->dmglog[i].dmg;
+ }
+ }
+ if(i<DAMAGELOG_SIZE)
+ md->dmglog[i].dmg+=(damage*battle_config.pet_attack_exp_rate)/100;
+ else {
+ md->dmglog[minpos].id=pd->msd->bl.id;
+ md->dmglog[minpos].dmg=(damage*battle_config.pet_attack_exp_rate)/100;
+ }
+ }
+ if(src && src->type == BL_MOB && ((struct mob_data*)src)->state.special_mob_ai){
+ struct mob_data *md2 = (struct mob_data *)src;
+ nullpo_retr(0, md2);
+ for(i=0,minpos=0,mindmg=0x7fffffff;i<DAMAGELOG_SIZE;i++){
+ if(md->dmglog[i].id==md2->master_id)
+ break;
+ if(md->dmglog[i].id==0){
+ minpos=i;
+ mindmg=0;
+ }
+ else if(md->dmglog[i].dmg<mindmg){
+ minpos=i;
+ mindmg=md->dmglog[i].dmg;
+ }
+ }
+ if(i<DAMAGELOG_SIZE)
+ md->dmglog[i].dmg+=damage;
+ else {
+ md->dmglog[minpos].id=md2->master_id;
+ md->dmglog[minpos].dmg=damage;
+
+ if(md->attacked_id <= 0 && md->state.special_mob_ai==0)
+ md->attacked_id = md2->master_id;
+ }
+ }
+
+ }
+
+ md->hp-=damage;
+
+ if(md->class >= 1285 && md->class <=1287) { // guardian hp update [Valaris]
+ struct guild_castle *gc=guild_mapname2gc(map[md->bl.m].name);
+ if(gc) {
+
+ if(md->bl.id==gc->GID0) {
+ gc->Ghp0=md->hp;
+ if(gc->Ghp0<=0) {
+ guild_castledatasave(gc->castle_id,10,0);
+ guild_castledatasave(gc->castle_id,18,0);
+ }
+ }
+ if(md->bl.id==gc->GID1) {
+ gc->Ghp1=md->hp;
+ if(gc->Ghp1<=0) {
+ guild_castledatasave(gc->castle_id,11,0);
+ guild_castledatasave(gc->castle_id,19,0);
+ }
+ }
+ if(md->bl.id==gc->GID2) {
+ gc->Ghp2=md->hp;
+ if(gc->Ghp2<=0) {
+ guild_castledatasave(gc->castle_id,12,0);
+ guild_castledatasave(gc->castle_id,20,0);
+ }
+ }
+ if(md->bl.id==gc->GID3) {
+ gc->Ghp3=md->hp;
+ if(gc->Ghp3<=0) {
+ guild_castledatasave(gc->castle_id,13,0);
+ guild_castledatasave(gc->castle_id,21,0);
+ }
+ }
+ if(md->bl.id==gc->GID4) {
+ gc->Ghp4=md->hp;
+ if(gc->Ghp4<=0) {
+ guild_castledatasave(gc->castle_id,14,0);
+ guild_castledatasave(gc->castle_id,22,0);
+ }
+ }
+ if(md->bl.id==gc->GID5) {
+ gc->Ghp5=md->hp;
+ if(gc->Ghp5<=0) {
+ guild_castledatasave(gc->castle_id,15,0);
+ guild_castledatasave(gc->castle_id,23,0);
+ }
+ }
+ if(md->bl.id==gc->GID6) {
+ gc->Ghp6=md->hp;
+ if(gc->Ghp6<=0) {
+ guild_castledatasave(gc->castle_id,16,0);
+ guild_castledatasave(gc->castle_id,24,0);
+ }
+ }
+ if(md->bl.id==gc->GID7) {
+ gc->Ghp7=md->hp;
+ if(gc->Ghp7<=0) {
+ guild_castledatasave(gc->castle_id,17,0);
+ guild_castledatasave(gc->castle_id,25,0);
+
+ }
+ }
+ }
+ } // end addition [Valaris]
+
+ if(md->option&2 )
+ skill_status_change_end(&md->bl, SC_HIDING, -1);
+ if(md->option&4 )
+ skill_status_change_end(&md->bl, SC_CLOAKING, -1);
+
+ if(md->state.special_mob_ai == 2){//スフィアーマイン
+ int skillidx=0;
+
+ if((skillidx=mob_skillid2skillidx(md->class,NPC_SELFDESTRUCTION2))>=0){
+ md->mode |= 0x1;
+ md->next_walktime=tick;
+ mobskill_use_id(md,&md->bl,skillidx);//自爆詠唱開始
+ md->state.special_mob_ai++;
+ }
+ }
+
+ if(md->hp>0){
+ return 0;
+ }
+
+ // ----- ここから死亡処理 -----
+
+ map_freeblock_lock();
+ mob_changestate(md,MS_DEAD,0);
+ mobskill_use(md,tick,-1); // 死亡時スキル
+
+ memset(tmpsd,0,sizeof(tmpsd));
+ memset(pt,0,sizeof(pt));
+
+ max_hp = battle_get_max_hp(&md->bl);
+
+ if(src && src->type == BL_MOB)
+ mob_unlocktarget((struct mob_data *)src,tick);
+
+ /* ソウルドレイン */
+ if(sd && (skill=pc_checkskill(sd,HW_SOULDRAIN))>0){
+ clif_skill_nodamage(src,&md->bl,HW_SOULDRAIN,skill,1);
+ sp = (battle_get_lv(&md->bl))*(65+15*skill)/100;
+ if(sd->status.sp + sp > sd->status.max_sp)
+ sp = sd->status.max_sp - sd->status.sp;
+ sd->status.sp += sp;
+ clif_heal(sd->fd,SP_SP,sp);
+ }
+
+ // map外に消えた人は計算から除くので
+ // overkill分は無いけどsumはmax_hpとは違う
+
+ tdmg = 0;
+ for(i=0,count=0,mvp_damage=0;i<DAMAGELOG_SIZE;i++){
+ if(md->dmglog[i].id==0)
+ continue;
+ tmpsd[i] = map_id2sd(md->dmglog[i].id);
+ if(tmpsd[i] == NULL)
+ continue;
+ count++;
+ if(tmpsd[i]->bl.m != md->bl.m || pc_isdead(tmpsd[i]))
+ continue;
+
+ tdmg += (double)md->dmglog[i].dmg;
+ if(mvp_damage<md->dmglog[i].dmg){
+ third_sd = second_sd;
+ second_sd = mvp_sd;
+ mvp_sd=tmpsd[i];
+ mvp_damage=md->dmglog[i].dmg;
+ }
+ }
+
+ // [MouseJstr]
+ if((map[md->bl.m].flag.pvp == 0) || (battle_config.pvp_exp == 1)) {
+
+ if((double)max_hp < tdmg)
+ dmg_rate = ((double)max_hp) / tdmg;
+ else dmg_rate = 1;
+
+ // 経験値の分配
+ for(i=0;i<DAMAGELOG_SIZE;i++){
+ int pid,base_exp,job_exp,flag=1;
+ double per;
+ struct party *p;
+ if(tmpsd[i]==NULL || tmpsd[i]->bl.m != md->bl.m)
+ continue;
+/* jAthena's exp formula
+ per = ((double)md->dmglog[i].dmg)*(9.+(double)((count > 6)? 6:count))/10./((double)max_hp) * dmg_rate;
+ temp = ((double)mob_db[md->class].base_exp * (double)battle_config.base_exp_rate / 100. * per);
+ base_exp = (temp > 2147483647.)? 0x7fffffff:(int)temp;
+ if(mob_db[md->class].base_exp > 0 && base_exp < 1) base_exp = 1;
+ if(base_exp < 0) base_exp = 0;
+ temp = ((double)mob_db[md->class].job_exp * (double)battle_config.job_exp_rate / 100. * per);
+ job_exp = (temp > 2147483647.)? 0x7fffffff:(int)temp;
+ if(mob_db[md->class].job_exp > 0 && job_exp < 1) job_exp = 1;
+ if(job_exp < 0) job_exp = 0;
+*/
+//eAthena's exp formula rather than jAthena's
+ per=(double)md->dmglog[i].dmg*256*(9+(double)((count > 6)? 6:count))/10/(double)max_hp;
+ if(per>512) per=512;
+ if(per<1) per=1;
+ base_exp=mob_db[md->class].base_exp*per/256;
+ if(base_exp < 1) base_exp = 1;
+ if(sd && md && battle_config.pk_mode==1 && (mob_db[md->class].lv - sd->status.base_level >= 20)) {
+ base_exp*=1.15; // pk_mode additional exp if monster >20 levels [Valaris]
+ }
+ if(md->state.special_mob_ai >= 1 && battle_config.alchemist_summon_reward != 1) base_exp = 0; // Added [Valaris]
+ job_exp=mob_db[md->class].job_exp*per/256;
+ if(job_exp < 1) job_exp = 1;
+ if(sd && md && battle_config.pk_mode==1 && (mob_db[md->class].lv - sd->status.base_level >= 20)) {
+ job_exp*=1.15; // pk_mode additional exp if monster >20 levels [Valaris]
+ }
+ if(md->state.special_mob_ai >= 1 && battle_config.alchemist_summon_reward != 1) job_exp = 0; // Added [Valaris]
+
+ if((pid=tmpsd[i]->status.party_id)>0){ // パーティに入っている
+ int j=0;
+ for(j=0;j<pnum;j++) // 公平パーティリストにいるかどうか
+ if(pt[j].id==pid)
+ break;
+ if(j==pnum){ // いないときは公平かどうか確認
+ if((p=party_search(pid))!=NULL && p->exp!=0){
+ pt[pnum].id=pid;
+ pt[pnum].p=p;
+ pt[pnum].base_exp=base_exp;
+ pt[pnum].job_exp=job_exp;
+ pnum++;
+ flag=0;
+ }
+ }else{ // いるときは公平
+ pt[j].base_exp+=base_exp;
+ pt[j].job_exp+=job_exp;
+ flag=0;
+ }
+ }
+ if(flag) // 各自所得
+ pc_gainexp(tmpsd[i],base_exp,job_exp);
+ }
+ // 公平分配
+ for(i=0;i<pnum;i++)
+ party_exp_share(pt[i].p,md->bl.m,pt[i].base_exp,pt[i].job_exp);
+
+ // item drop
+ if(!(type&1)) {
+ int log_item[8] = {0};
+ for(i=0;i<8;i++){
+ struct delay_item_drop *ditem;
+ int drop_rate;
+
+ if(md->state.special_mob_ai >= 1 && battle_config.alchemist_summon_reward != 1) // Added [Valaris]
+ break; // End
+
+ if(mob_db[md->class].dropitem[i].nameid <= 0)
+ continue;
+ drop_rate = mob_db[md->class].dropitem[i].p;
+ if(drop_rate <= 0 && battle_config.drop_rate0item==1)
+ drop_rate = 1;
+ if(battle_config.drops_by_luk>0 && sd && md) drop_rate+=(sd->status.luk*battle_config.drops_by_luk)/100; // drops affected by luk [Valaris]
+ if(sd && md && battle_config.pk_mode==1 && (mob_db[md->class].lv - sd->status.base_level >= 20)) drop_rate*=1.25; // pk_mode increase drops if 20 level difference [Valaris]
+ if(drop_rate <= rand()%10000)
+ continue;
+
+ ditem=(struct delay_item_drop *)aCalloc(1,sizeof(struct delay_item_drop));
+ ditem->nameid = mob_db[md->class].dropitem[i].nameid;
+ log_item[i] = ditem->nameid;
+ ditem->amount = 1;
+ ditem->m = md->bl.m;
+ ditem->x = md->bl.x;
+ ditem->y = md->bl.y;
+ ditem->first_sd = mvp_sd;
+ ditem->second_sd = second_sd;
+ ditem->third_sd = third_sd;
+ add_timer(tick+500+i,mob_delay_item_drop,(int)ditem,0);
+ }
+
+ #ifndef TXT_ONLY
+ if(log_config.drop > 0)
+ log_drop(mvp_sd, md->class, log_item);
+ #endif
+
+ if(sd && sd->state.attack_type == BF_WEAPON) {
+ for(i=0;i<sd->monster_drop_item_count;i++) {
+ struct delay_item_drop *ditem;
+ int race = battle_get_race(&md->bl);
+ if(sd->monster_drop_itemid[i] <= 0)
+ continue;
+ if(sd->monster_drop_race[i] & (1<<race) ||
+ (mob_db[md->class].mode & 0x20 && sd->monster_drop_race[i] & 1<<10) ||
+ (!(mob_db[md->class].mode & 0x20) && sd->monster_drop_race[i] & 1<<11) ) {
+ if(sd->monster_drop_itemrate[i] <= rand()%10000)
+ continue;
+
+ ditem=(struct delay_item_drop *)aCalloc(1,sizeof(struct delay_item_drop));
+ ditem->nameid = sd->monster_drop_itemid[i];
+ ditem->amount = 1;
+ ditem->m = md->bl.m;
+ ditem->x = md->bl.x;
+ ditem->y = md->bl.y;
+ ditem->first_sd = mvp_sd;
+ ditem->second_sd = second_sd;
+ ditem->third_sd = third_sd;
+ add_timer(tick+520+i,mob_delay_item_drop,(int)ditem,0);
+ }
+ }
+ if(sd->get_zeny_num > 0)
+ pc_getzeny(sd,mob_db[md->class].lv*10 + rand()%(sd->get_zeny_num+1));
+ }
+ if(md->lootitem) {
+ for(i=0;i<md->lootitem_count;i++) {
+ struct delay_item_drop2 *ditem;
+
+ ditem=(struct delay_item_drop2 *)aCalloc(1,sizeof(struct delay_item_drop2));
+ memcpy(&ditem->item_data,&md->lootitem[i],sizeof(md->lootitem[0]));
+ ditem->m = md->bl.m;
+ ditem->x = md->bl.x;
+ ditem->y = md->bl.y;
+ ditem->first_sd = mvp_sd;
+ ditem->second_sd = second_sd;
+ ditem->third_sd = third_sd;
+ add_timer(tick+540+i,mob_delay_item_drop2,(int)ditem,0);
+ }
+ }
+ }
+
+ // mvp処理
+ if(mvp_sd && mob_db[md->class].mexp > 0 ){
+ int log_mvp[2] = {0};
+ int j;
+ int mexp;
+ temp = ((double)mob_db[md->class].mexp * (double)battle_config.mvp_exp_rate * (9.+(double)count)/1000.);
+ mexp = (temp > 2147483647.)? 0x7fffffff:(int)temp;
+ if(mexp < 1) mexp = 1;
+ clif_mvp_effect(mvp_sd); // エフェクト
+ clif_mvp_exp(mvp_sd,mexp);
+ pc_gainexp(mvp_sd,mexp,0);
+ log_mvp[1] = mexp;
+ for(j=0;j<3;j++){
+ i = rand() % 3;
+ if(mob_db[md->class].mvpitem[i].nameid <= 0)
+ continue;
+ drop_rate = mob_db[md->class].mvpitem[i].p;
+ if(drop_rate <= 0 && battle_config.drop_rate0item==1)
+ drop_rate = 1;
+ if(drop_rate < battle_config.item_drop_mvp_min)
+ drop_rate = battle_config.item_drop_mvp_min;
+ if(drop_rate > battle_config.item_drop_mvp_max)
+ drop_rate = battle_config.item_drop_mvp_max;
+ if(drop_rate <= rand()%10000)
+ continue;
+ memset(&item,0,sizeof(item));
+ item.nameid=mob_db[md->class].mvpitem[i].nameid;
+ item.identify=!itemdb_isequip3(item.nameid);
+ clif_mvp_item(mvp_sd,item.nameid);
+ log_mvp[0] = item.nameid;
+ if(mvp_sd->weight*2 > mvp_sd->max_weight)
+ map_addflooritem(&item,1,mvp_sd->bl.m,mvp_sd->bl.x,mvp_sd->bl.y,mvp_sd,second_sd,third_sd,1);
+ else if((ret = pc_additem(mvp_sd,&item,1))) {
+ clif_additem(sd,0,0,ret);
+ map_addflooritem(&item,1,mvp_sd->bl.m,mvp_sd->bl.x,mvp_sd->bl.y,mvp_sd,second_sd,third_sd,1);
+ }
+ break;
+ }
+ #ifndef TXT_ONLY
+ if(log_config.mvpdrop > 0)
+ log_mvpdrop(mvp_sd, md->class, log_mvp);
+ #endif
+ }
+
+ } // [MouseJstr]
+
+ // <Agit> NPC Event [OnAgitBreak]
+ if(md->npc_event[0] && strcmp(((md->npc_event)+strlen(md->npc_event)-13),"::OnAgitBreak") == 0) {
+ printf("MOB.C: Run NPC_Event[OnAgitBreak].\n");
+ if (agit_flag == 1) //Call to Run NPC_Event[OnAgitBreak]
+ guild_agit_break(md);
+ }
+
+ // SCRIPT実行
+ if(md->npc_event[0]){
+// if(battle_config.battle_log==1)
+// printf("mob_damage : run event : %s\n",md->npc_event);
+ if(src && src->type == BL_PET)
+ sd = ((struct pet_data *)src)->msd;
+ if(sd == NULL) {
+ if(mvp_sd != NULL)
+ sd = mvp_sd;
+ else {
+ struct map_session_data *tmpsd;
+ int i;
+ for(i=0;i<fd_max;i++){
+ if(session[i] && (tmpsd=session[i]->session_data) && tmpsd->state.auth) {
+ if(md->bl.m == tmpsd->bl.m) {
+ sd = tmpsd;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if(sd)
+ npc_event(sd,md->npc_event,0);
+ }
+
+ clif_clearchar_area(&md->bl,1);
+ map_delblock(&md->bl);
+ if(mob_get_viewclass(md->class) <= 1000)
+ clif_clearchar_delay(tick+3000,&md->bl,0);
+ mob_deleteslave(md);
+ mob_setdelayspawn(md->bl.id);
+ map_freeblock_unlock();
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int mob_class_change(struct mob_data *md,int *value)
+{
+ unsigned int tick = gettick();
+ int i,c,hp_rate,max_hp,class,count = 0;
+
+ nullpo_retr(0, md);
+ nullpo_retr(0, value);
+
+ if(value[0]<=1000 || value[0]>2000)
+ return 0;
+ if(md->bl.prev == NULL) return 0;
+
+ while(count < 5 && value[count] > 1000 && value[count] <= 2000) count++;
+ if(count < 1) return 0;
+
+ class = value[rand()%count];
+ if(class<=1000 || class>2000) return 0;
+
+ max_hp = battle_get_max_hp(&md->bl);
+ hp_rate = md->hp*100/max_hp;
+ clif_mob_class_change(md,class);
+ md->class = class;
+ max_hp = battle_get_max_hp(&md->bl);
+ if(battle_config.monster_class_change_full_recover==1) {
+ md->hp = max_hp;
+ memset(md->dmglog,0,sizeof(md->dmglog));
+ }
+ else
+ md->hp = max_hp*hp_rate/100;
+ if(md->hp > max_hp) md->hp = max_hp;
+ else if(md->hp < 1) md->hp = 1;
+
+ memcpy(md->name,mob_db[class].jname,24);
+ memset(&md->state,0,sizeof(md->state));
+ md->attacked_id = 0;
+ md->target_id = 0;
+ md->move_fail_count = 0;
+
+ md->speed = mob_db[md->class].speed;
+ md->def_ele = mob_db[md->class].element;
+
+ mob_changestate(md,MS_IDLE,0);
+ skill_castcancel(&md->bl,0);
+ md->state.skillstate = MSS_IDLE;
+ md->last_thinktime = tick;
+ md->next_walktime = tick+rand()%50+5000;
+ md->attackabletime = tick;
+ md->canmove_tick = tick;
+ md->sg_count=0;
+
+ for(i=0,c=tick-1000*3600*10;i<MAX_MOBSKILL;i++)
+ md->skilldelay[i] = c;
+ md->skillid=0;
+ md->skilllv=0;
+
+ if(md->lootitem == NULL && mob_db[class].mode&0x02)
+ md->lootitem=(struct item *)aCalloc(LOOTITEM_SIZE,sizeof(struct item));
+
+ skill_clear_unitgroup(&md->bl);
+ skill_cleartimerskill(&md->bl);
+
+ clif_clearchar_area(&md->bl,0);
+ clif_spawnmob(md);
+
+ return 0;
+}
+
+/*==========================================
+ * mob回復
+ *------------------------------------------
+ */
+int mob_heal(struct mob_data *md,int heal)
+{
+ int max_hp = battle_get_max_hp(&md->bl);
+
+ nullpo_retr(0, md);
+
+ md->hp += heal;
+ if( max_hp < md->hp )
+ md->hp = max_hp;
+
+ if(md->class >= 1285 && md->class <=1287) { // guardian hp update [Valaris]
+ struct guild_castle *gc=guild_mapname2gc(map[md->bl.m].name);
+ if(gc) {
+ if(md->bl.id==gc->GID0) gc->Ghp0=md->hp;
+ if(md->bl.id==gc->GID1) gc->Ghp1=md->hp;
+ if(md->bl.id==gc->GID2) gc->Ghp2=md->hp;
+ if(md->bl.id==gc->GID3) gc->Ghp3=md->hp;
+ if(md->bl.id==gc->GID4) gc->Ghp4=md->hp;
+ if(md->bl.id==gc->GID5) gc->Ghp5=md->hp;
+ if(md->bl.id==gc->GID6) gc->Ghp6=md->hp;
+ if(md->bl.id==gc->GID7) gc->Ghp7=md->hp;
+ }
+ } // end addition [Valaris]
+
+ return 0;
+}
+
+
+/*==========================================
+ * Added by RoVeRT
+ *------------------------------------------
+ */
+int mob_warpslave_sub(struct block_list *bl,va_list ap)
+{
+ struct mob_data *md=(struct mob_data *)bl;
+ int id,x,y;
+ id=va_arg(ap,int);
+ x=va_arg(ap,int);
+ y=va_arg(ap,int);
+ if( md->master_id==id ) {
+ mob_warp(md,-1,x,y,2);
+ }
+ return 0;
+}
+
+/*==========================================
+ * Added by RoVeRT
+ *------------------------------------------
+ */
+int mob_warpslave(struct mob_data *md,int x, int y)
+{
+//printf("warp slave\n");
+ map_foreachinarea(mob_warpslave_sub, md->bl.m,
+ x-AREA_SIZE,y-AREA_SIZE,
+ x+AREA_SIZE,y+AREA_SIZE,BL_MOB,
+ md->bl.id, md->bl.x, md->bl.y );
+ return 0;
+}
+
+/*==========================================
+ * mobワープ
+ *------------------------------------------
+ */
+int mob_warp(struct mob_data *md,int m,int x,int y,int type)
+{
+ int i=0,c,xs=0,ys=0,bx=x,by=y;
+
+ nullpo_retr(0, md);
+
+ if( md->bl.prev==NULL )
+ return 0;
+
+ if( m<0 ) m=md->bl.m;
+
+ if(type >= 0) {
+ if(map[md->bl.m].flag.monster_noteleport)
+ return 0;
+ clif_clearchar_area(&md->bl,type);
+ }
+ skill_unit_out_all(&md->bl,gettick(),1);
+ map_delblock(&md->bl);
+
+ if(bx>0 && by>0){ // 位置指定の場合周囲9セルを探索
+ xs=ys=9;
+ }
+
+ while( ( x<0 || y<0 || ((c=read_gat(m,x,y))==1 || c==5) ) && (i++)<1000 ){
+ if( xs>0 && ys>0 && i<250 ){ // 指定位置付近の探索
+ x=bx+rand()%xs-xs/2;
+ y=by+rand()%ys-ys/2;
+ }else{ // 完全ランダム探索
+ x=rand()%(map[m].xs-2)+1;
+ y=rand()%(map[m].ys-2)+1;
+ }
+ }
+ md->dir=0;
+ if(i<1000){
+ md->bl.x=md->to_x=x;
+ md->bl.y=md->to_y=y;
+ md->bl.m=m;
+ }else {
+ m=md->bl.m;
+ if(battle_config.error_log==1)
+ printf("MOB %d warp failed, class = %d\n",md->bl.id,md->class);
+ }
+
+ md->target_id=0; // タゲを解除する
+ md->state.targettype=NONE_ATTACKABLE;
+ md->attacked_id=0;
+ md->state.skillstate=MSS_IDLE;
+ mob_changestate(md,MS_IDLE,0);
+
+ if(type>0 && i==1000) {
+ if(battle_config.battle_log==1)
+ printf("MOB %d warp to (%d,%d), class = %d\n",md->bl.id,x,y,md->class);
+ }
+
+ map_addblock(&md->bl);
+ if(type>0) {
+ clif_spawnmob(md);
+ mob_warpslave(md,md->bl.x,md->bl.y);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 画面内の取り巻きの数計算用(foreachinarea)
+ *------------------------------------------
+ */
+int mob_countslave_sub(struct block_list *bl,va_list ap)
+{
+ int id,*c;
+ struct mob_data *md;
+
+ id=va_arg(ap,int);
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, c=va_arg(ap,int *));
+ nullpo_retr(0, md = (struct mob_data *)bl);
+
+
+ if( md->master_id==id )
+ (*c)++;
+ return 0;
+}
+/*==========================================
+ * 画面内の取り巻きの数計算
+ *------------------------------------------
+ */
+int mob_countslave(struct mob_data *md)
+{
+ int c=0;
+
+ nullpo_retr(0, md);
+
+ map_foreachinarea(mob_countslave_sub, md->bl.m,
+ 0,0,map[md->bl.m].xs-1,map[md->bl.m].ys-1,
+ BL_MOB,md->bl.id,&c);
+ return c;
+}
+/*==========================================
+ * 手下MOB召喚
+ *------------------------------------------
+ */
+int mob_summonslave(struct mob_data *md2,int *value,int amount,int flag)
+{
+ struct mob_data *md;
+ int bx,by,m,count = 0,class,k,a = amount;
+
+ nullpo_retr(0, md2);
+ nullpo_retr(0, value);
+
+ bx=md2->bl.x;
+ by=md2->bl.y;
+ m=md2->bl.m;
+
+ if(value[0]<=1000 || value[0]>2000) // 値が異常なら召喚を止める
+ return 0;
+ while(count < 5 && value[count] > 1000 && value[count] <= 2000) count++;
+ if(count < 1) return 0;
+
+ for(k=0;k<count;k++) {
+ amount = a;
+ class = value[k];
+ if(class<=1000 || class>2000) continue;
+ for(;amount>0;amount--){
+ int x=0,y=0,c=0,i=0;
+ md=(struct mob_data *)aCalloc(1,sizeof(struct mob_data));
+ if(mob_db[class].mode&0x02)
+ md->lootitem=(struct item *)aCalloc(LOOTITEM_SIZE,sizeof(struct item));
+ else
+ md->lootitem=NULL;
+
+ while((x<=0 || y<=0 || (c=map_getcell(m,x,y))==1 || c==5 ) && (i++)<100){
+ x=rand()%9-4+bx;
+ y=rand()%9-4+by;
+ }
+ if(i>=100){
+ x=bx;
+ y=by;
+ }
+
+ mob_spawn_dataset(md,"--ja--",class);
+ md->bl.m=m;
+ md->bl.x=x;
+ md->bl.y=y;
+
+ md->m =m;
+ md->x0=x;
+ md->y0=y;
+ md->xs=0;
+ md->ys=0;
+ md->speed=md2->speed;
+ md->spawndelay1=-1; // 一度のみフラグ
+ md->spawndelay2=-1; // 一度のみフラグ
+
+ memset(md->npc_event,0,sizeof(md->npc_event));
+ md->bl.type=BL_MOB;
+ map_addiddb(&md->bl);
+ mob_spawn(md->bl.id);
+ clif_skill_nodamage(&md->bl,&md->bl,(flag)? NPC_SUMMONSLAVE:NPC_SUMMONMONSTER,a,1);
+
+ if(flag)
+ md->master_id=md2->bl.id;
+ }
+ }
+ return 0;
+}
+
+/*==========================================
+ * 自分をロックしているPCの数を数える(foreachclient)
+ *------------------------------------------
+ */
+static int mob_counttargeted_sub(struct block_list *bl,va_list ap)
+{
+ int id,*c,target_lv;
+ struct block_list *src;
+
+ id=va_arg(ap,int);
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, c=va_arg(ap,int *));
+
+ src=va_arg(ap,struct block_list *);
+ target_lv=va_arg(ap,int);
+ if(id == bl->id || (src && id == src->id)) return 0;
+ if(bl->type == BL_PC) {
+ struct map_session_data *sd = (struct map_session_data *)bl;
+ if(sd && sd->attacktarget == id && sd->attacktimer != -1 && sd->attacktarget_lv >= target_lv)
+ (*c)++;
+ }
+ else if(bl->type == BL_MOB) {
+ struct mob_data *md = (struct mob_data *)bl;
+ if(md && md->target_id == id && md->timer != -1 && md->state.state == MS_ATTACK && md->target_lv >= target_lv)
+ (*c)++;
+ }
+ else if(bl->type == BL_PET) {
+ struct pet_data *pd = (struct pet_data *)bl;
+ if(pd->target_id == id && pd->timer != -1 && pd->state.state == MS_ATTACK && pd->target_lv >= target_lv)
+ (*c)++;
+ }
+ return 0;
+}
+/*==========================================
+ * 自分をロックしているPCの数を数える
+ *------------------------------------------
+ */
+int mob_counttargeted(struct mob_data *md,struct block_list *src,int target_lv)
+{
+ int c=0;
+
+ nullpo_retr(0, md);
+
+ map_foreachinarea(mob_counttargeted_sub, md->bl.m,
+ md->bl.x-AREA_SIZE,md->bl.y-AREA_SIZE,
+ md->bl.x+AREA_SIZE,md->bl.y+AREA_SIZE,0,md->bl.id,&c,src,target_lv);
+ return c;
+}
+
+/*==========================================
+ *MOBskillから該当skillidのskillidxを返す
+ *------------------------------------------
+ */
+int mob_skillid2skillidx(int class,int skillid)
+{
+ int i;
+ struct mob_skill *ms=mob_db[class].skill;
+
+ if(ms==NULL)
+ return -1;
+
+ for(i=0;i<mob_db[class].maxskill;i++){
+ if(ms[i].skill_id == skillid)
+ return i;
+ }
+ return -1;
+
+}
+
+//
+// MOBスキル
+//
+
+/*==========================================
+ * スキル使用(詠唱完了、ID指定)
+ *------------------------------------------
+ */
+int mobskill_castend_id( int tid, unsigned int tick, int id,int data )
+{
+ struct mob_data* md=NULL;
+ struct block_list *bl;
+ struct block_list *mbl;
+ int range;
+
+ if((mbl = map_id2bl(id)) == NULL ) //詠唱したMobがもういないというのは良くある正常処理
+ return 0;
+ if((md=(struct mob_data *)mbl) == NULL ){
+ printf("mobskill_castend_id nullpo mbl->id:%d\n",mbl->id);
+ return 0;
+ }
+
+ if( md->bl.type!=BL_MOB || md->bl.prev==NULL )
+ return 0;
+
+ if( md->skilltimer != tid ) // タイマIDの確認
+ return 0;
+
+ md->skilltimer=-1;
+ //沈黙や状態異常など
+ if(md->sc_data){
+ if(md->opt1>0 || md->sc_data[SC_DIVINA].timer != -1 || md->sc_data[SC_ROKISWEIL].timer != -1 || md->sc_data[SC_STEELBODY].timer != -1)
+ return 0;
+ if(md->sc_data[SC_AUTOCOUNTER].timer != -1 && md->skillid != KN_AUTOCOUNTER) //オートカウンター
+ return 0;
+ if(md->sc_data[SC_BLADESTOP].timer != -1) //白刃取り
+ return 0;
+ if(md->sc_data[SC_BERSERK].timer != -1) //バーサーク
+ return 0;
+ }
+ if(md->skillid != NPC_EMOTION)
+ md->last_thinktime=tick + battle_get_adelay(&md->bl);
+
+ if((bl = map_id2bl(md->skilltarget)) == NULL || bl->prev==NULL){ //スキルターゲットが存在しない
+ //printf("mobskill_castend_id nullpo\n");//ターゲットがいないときはnullpoじゃなくて普通に終了
+ return 0;
+ }
+ if(md->bl.m != bl->m)
+ return 0;
+
+ if(md->skillid == PR_LEXAETERNA) {
+ struct status_change *sc_data = battle_get_sc_data(bl);
+ if(sc_data && (sc_data[SC_FREEZE].timer != -1 || (sc_data[SC_STONE].timer != -1 && sc_data[SC_STONE].val2 == 0)))
+ return 0;
+ }
+ else if(md->skillid == RG_BACKSTAP) {
+ int dir = map_calc_dir(&md->bl,bl->x,bl->y),t_dir = battle_get_dir(bl);
+ int dist = distance(md->bl.x,md->bl.y,bl->x,bl->y);
+ if(bl->type != BL_SKILL && (dist == 0 || map_check_dir(dir,t_dir)))
+ return 0;
+ }
+ if( ( (skill_get_inf(md->skillid)&1) || (skill_get_inf2(md->skillid)&4) ) && // 彼我敵対関係チェック
+ battle_check_target(&md->bl,bl, BCT_ENEMY)<=0 )
+ return 0;
+ range = skill_get_range(md->skillid,md->skilllv);
+ if(range < 0)
+ range = battle_get_range(&md->bl) - (range + 1);
+ if(range + battle_config.mob_skill_add_range < distance(md->bl.x,md->bl.y,bl->x,bl->y))
+ return 0;
+
+ md->skilldelay[md->skillidx]=tick;
+
+ if(battle_config.mob_skill_log==1)
+ printf("MOB skill castend skill=%d, class = %d\n",md->skillid,md->class);
+ mob_stop_walking(md,0);
+
+ switch( skill_get_nk(md->skillid) )
+ {
+ // 攻撃系/吹き飛ばし系
+ case 0: case 2:
+ skill_castend_damage_id(&md->bl,bl,md->skillid,md->skilllv,tick,0);
+ break;
+ case 1:// 支援系
+ if(!mob_db[md->class].skill[md->skillidx].val[0] &&
+ (md->skillid==AL_HEAL || (md->skillid==ALL_RESURRECTION && bl->type != BL_PC)) && battle_check_undead(battle_get_race(bl),battle_get_elem_type(bl)) )
+ skill_castend_damage_id(&md->bl,bl,md->skillid,md->skilllv,tick,0);
+ else
+ skill_castend_nodamage_id(&md->bl,bl,md->skillid,md->skilllv,tick,0);
+ break;
+ }
+
+
+ return 0;
+}
+
+/*==========================================
+ * スキル使用(詠唱完了、場所指定)
+ *------------------------------------------
+ */
+int mobskill_castend_pos( int tid, unsigned int tick, int id,int data )
+{
+ struct mob_data* md=NULL;
+ struct block_list *bl;
+ int range,maxcount;
+
+ //mobskill_castend_id同様詠唱したMobが詠唱完了時にもういないというのはありそうなのでnullpoから除外
+ if((bl=map_id2bl(id))==NULL)
+ return 0;
+
+ nullpo_retr(0, md=(struct mob_data *)bl);
+
+ if( md->bl.type!=BL_MOB || md->bl.prev==NULL )
+ return 0;
+
+ if( md->skilltimer != tid ) // タイマIDの確認
+ return 0;
+
+ md->skilltimer=-1;
+ if(md->sc_data){
+ if(md->opt1>0 || md->sc_data[SC_DIVINA].timer != -1 || md->sc_data[SC_ROKISWEIL].timer != -1 || md->sc_data[SC_STEELBODY].timer != -1)
+ return 0;
+ if(md->sc_data[SC_AUTOCOUNTER].timer != -1 && md->skillid != KN_AUTOCOUNTER) //オートカウンター
+ return 0;
+ if(md->sc_data[SC_BLADESTOP].timer != -1) //白刃取り
+ return 0;
+ if(md->sc_data[SC_BERSERK].timer != -1) //バーサーク
+ return 0;
+ }
+
+ if(battle_config.monster_skill_reiteration == 0) {
+ range = -1;
+ switch(md->skillid) {
+ case MG_SAFETYWALL:
+ case WZ_FIREPILLAR:
+ case HT_SKIDTRAP:
+ case HT_LANDMINE:
+ case HT_ANKLESNARE:
+ case HT_SHOCKWAVE:
+ case HT_SANDMAN:
+ case HT_FLASHER:
+ case HT_FREEZINGTRAP:
+ case HT_BLASTMINE:
+ case HT_CLAYMORETRAP:
+ case PF_SPIDERWEB: /* スパイダーウェッブ */
+ range = 0;
+ break;
+ case AL_PNEUMA:
+ case AL_WARP:
+ range = 1;
+ break;
+ }
+ if(range >= 0) {
+ if(skill_check_unit_range(md->bl.m,md->skillx,md->skilly,range,md->skillid) > 0)
+ return 0;
+ }
+ }
+ if(battle_config.monster_skill_nofootset==1) {
+ range = -1;
+ switch(md->skillid) {
+ case WZ_FIREPILLAR:
+ case HT_SKIDTRAP:
+ case HT_LANDMINE:
+ case HT_ANKLESNARE:
+ case HT_SHOCKWAVE:
+ case HT_SANDMAN:
+ case HT_FLASHER:
+ case HT_FREEZINGTRAP:
+ case HT_BLASTMINE:
+ case HT_CLAYMORETRAP:
+ case AM_DEMONSTRATION:
+ case PF_SPIDERWEB: /* スパイダーウェッブ */
+ range = 1;
+ break;
+ case AL_WARP:
+ range = 0;
+ break;
+ }
+ if(range >= 0) {
+ if(skill_check_unit_range2(md->bl.m,md->skillx,md->skilly,range) > 0)
+ return 0;
+ }
+ }
+
+ if(battle_config.monster_land_skill_limit==1) {
+ maxcount = skill_get_maxcount(md->skillid);
+ if(maxcount > 0) {
+ int i,c;
+ for(i=c=0;i<MAX_MOBSKILLUNITGROUP;i++) {
+ if(md->skillunit[i].alive_count > 0 && md->skillunit[i].skill_id == md->skillid)
+ c++;
+ }
+ if(c >= maxcount)
+ return 0;
+ }
+ }
+
+ range = skill_get_range(md->skillid,md->skilllv);
+ if(range < 0)
+ range = battle_get_range(&md->bl) - (range + 1);
+ if(range + battle_config.mob_skill_add_range < distance(md->bl.x,md->bl.y,md->skillx,md->skilly))
+ return 0;
+ md->skilldelay[md->skillidx]=tick;
+
+ if(battle_config.mob_skill_log==1)
+ printf("MOB skill castend skill=%d, class = %d\n",md->skillid,md->class);
+ mob_stop_walking(md,0);
+
+ skill_castend_pos2(&md->bl,md->skillx,md->skilly,md->skillid,md->skilllv,tick,0);
+
+ return 0;
+}
+
+
+/*==========================================
+ * Skill use (an aria start, ID specification)
+ *------------------------------------------
+ */
+int mobskill_use_id(struct mob_data *md,struct block_list *target,int skill_idx)
+{
+ int casttime,range;
+ struct mob_skill *ms;
+ int skill_id, skill_lv, forcecast = 0;
+
+ nullpo_retr(0, md);
+ nullpo_retr(0, ms=&mob_db[md->class].skill[skill_idx]);
+
+ if( target==NULL && (target=map_id2bl(md->target_id))==NULL )
+ return 0;
+
+ if( target->prev==NULL || md->bl.prev==NULL )
+ return 0;
+
+ skill_id=ms->skill_id;
+ skill_lv=ms->skill_lv;
+
+ // 沈黙や異常
+ if(md->sc_data){
+ if(md->opt1>0 || md->sc_data[SC_DIVINA].timer != -1 || md->sc_data[SC_ROKISWEIL].timer != -1 || md->sc_data[SC_STEELBODY].timer != -1)
+ return 0;
+ if(md->sc_data[SC_AUTOCOUNTER].timer != -1 && md->skillid != KN_AUTOCOUNTER) //オートカウンター
+ return 0;
+ if(md->sc_data[SC_BLADESTOP].timer != -1) //白刃取り
+ return 0;
+ if(md->sc_data[SC_BERSERK].timer != -1) //バーサーク
+ return 0;
+ }
+
+ if(md->option&4 && skill_id==TF_HIDING)
+ return 0;
+ if(md->option&2 && skill_id!=TF_HIDING && skill_id!=AS_GRIMTOOTH && skill_id!=RG_BACKSTAP && skill_id!=RG_RAID)
+ return 0;
+
+ if(map[md->bl.m].flag.gvg && (skill_id == SM_ENDURE || skill_id == AL_TELEPORT || skill_id == AL_WARP ||
+ skill_id == WZ_ICEWALL || skill_id == TF_BACKSLIDING))
+ return 0;
+
+ if(skill_get_inf2(skill_id)&0x200 && md->bl.id == target->id)
+ return 0;
+
+ // 射程と障害物チェック
+ range = skill_get_range(skill_id,skill_lv);
+ if(range < 0)
+ range = battle_get_range(&md->bl) - (range + 1);
+ if(!battle_check_range(&md->bl,target,range))
+ return 0;
+
+// delay=skill_delayfix(&md->bl, skill_get_delay( skill_id,skill_lv) );
+
+ casttime=skill_castfix(&md->bl,ms->casttime);
+ md->state.skillcastcancel=ms->cancel;
+ md->skilldelay[skill_idx]=gettick();
+
+ switch(skill_id){ /* 何か特殊な処理が必要 */
+ case ALL_RESURRECTION: /* リザレクション */
+ if(target->type != BL_PC && battle_check_undead(battle_get_race(target),battle_get_elem_type(target))){ /* 敵がアンデッドなら */
+ forcecast=1; /* ターンアンデットと同じ詠唱時間 */
+ casttime=skill_castfix(&md->bl, skill_get_cast(PR_TURNUNDEAD,skill_lv) );
+ }
+ break;
+ case MO_EXTREMITYFIST: /*阿修羅覇鳳拳*/
+ case SA_MAGICROD:
+ case SA_SPELLBREAKER:
+ forcecast=1;
+ break;
+ }
+
+ if(battle_config.mob_skill_log==1)
+ printf("MOB skill use target_id=%d skill=%d lv=%d cast=%d, class = %d\n",target->id,skill_id,skill_lv,casttime,md->class);
+
+ if(casttime>0 || forcecast){ // 詠唱が必要
+// struct mob_data *md2;
+ clif_skillcasting( &md->bl,
+ md->bl.id, target->id, 0,0, skill_id,casttime);
+
+ // 詠唱反応モンスター
+/* if( target->type==BL_MOB && mob_db[(md2=(struct mob_data *)target)->class].mode&0x10 &&
+ md2->state.state!=MS_ATTACK){
+ md2->target_id=md->bl.id;
+ md->state.targettype = ATTACKABLE;
+ md2->min_chase=13;
+ }*/
+ }
+
+ if( casttime<=0 ) // 詠唱の無いものはキャンセルされない
+ md->state.skillcastcancel=0;
+
+ md->skilltarget = target->id;
+ md->skillx = 0;
+ md->skilly = 0;
+ md->skillid = skill_id;
+ md->skilllv = skill_lv;
+ md->skillidx = skill_idx;
+
+ if(!(battle_config.monster_cloak_check_type&2) && md->sc_data[SC_CLOAKING].timer != -1 && md->skillid != AS_CLOAKING)
+ skill_status_change_end(&md->bl,SC_CLOAKING,-1);
+
+ if( casttime>0 ){
+ md->skilltimer =
+ add_timer( gettick()+casttime, mobskill_castend_id, md->bl.id, 0 );
+ }else{
+ md->skilltimer = -1;
+ mobskill_castend_id(md->skilltimer,gettick(),md->bl.id, 0);
+ }
+
+ return 1;
+}
+/*==========================================
+ * スキル使用(場所指定)
+ *------------------------------------------
+ */
+int mobskill_use_pos( struct mob_data *md,
+ int skill_x, int skill_y, int skill_idx)
+{
+ int casttime=0,range;
+ struct mob_skill *ms;
+ struct block_list bl;
+ int skill_id, skill_lv;
+
+ nullpo_retr(0, md);
+ nullpo_retr(0, ms=&mob_db[md->class].skill[skill_idx]);
+
+ if( md->bl.prev==NULL )
+ return 0;
+
+ skill_id=ms->skill_id;
+ skill_lv=ms->skill_lv;
+
+ //沈黙や状態異常など
+ if(md->sc_data){
+ if(md->opt1>0 || md->sc_data[SC_DIVINA].timer != -1 || md->sc_data[SC_ROKISWEIL].timer != -1 || md->sc_data[SC_STEELBODY].timer != -1)
+ return 0;
+ if(md->sc_data[SC_AUTOCOUNTER].timer != -1 && md->skillid != KN_AUTOCOUNTER) //オートカウンター
+ return 0;
+ if(md->sc_data[SC_BLADESTOP].timer != -1) //白刃取り
+ return 0;
+ if(md->sc_data[SC_BERSERK].timer != -1) //バーサーク
+ return 0;
+ }
+
+ if(md->option&2)
+ return 0;
+
+ if(map[md->bl.m].flag.gvg && (skill_id == SM_ENDURE || skill_id == AL_TELEPORT || skill_id == AL_WARP ||
+ skill_id == WZ_ICEWALL || skill_id == TF_BACKSLIDING))
+ return 0;
+
+ // 射程と障害物チェック
+ bl.type = BL_NUL;
+ bl.m = md->bl.m;
+ bl.x = skill_x;
+ bl.y = skill_y;
+ range = skill_get_range(skill_id,skill_lv);
+ if(range < 0)
+ range = battle_get_range(&md->bl) - (range + 1);
+ if(!battle_check_range(&md->bl,&bl,range))
+ return 0;
+
+// delay=skill_delayfix(&sd->bl, skill_get_delay( skill_id,skill_lv) );
+ casttime=skill_castfix(&md->bl,ms->casttime);
+ md->skilldelay[skill_idx]=gettick();
+ md->state.skillcastcancel=ms->cancel;
+
+ if(battle_config.mob_skill_log==1)
+ printf("MOB skill use target_pos=(%d,%d) skill=%d lv=%d cast=%d, class = %d\n",
+ skill_x,skill_y,skill_id,skill_lv,casttime,md->class);
+
+ if( casttime>0 ) // A cast time is required.
+ clif_skillcasting( &md->bl,
+ md->bl.id, 0, skill_x,skill_y, skill_id,casttime);
+
+ if( casttime<=0 ) // A skill without a cast time wont be cancelled.
+ md->state.skillcastcancel=0;
+
+
+ md->skillx = skill_x;
+ md->skilly = skill_y;
+ md->skilltarget = 0;
+ md->skillid = skill_id;
+ md->skilllv = skill_lv;
+ md->skillidx = skill_idx;
+ if(!(battle_config.monster_cloak_check_type&2) && md->sc_data[SC_CLOAKING].timer != -1)
+ skill_status_change_end(&md->bl,SC_CLOAKING,-1);
+ if( casttime>0 ){
+ md->skilltimer =
+ add_timer( gettick()+casttime, mobskill_castend_pos, md->bl.id, 0 );
+ }else{
+ md->skilltimer = -1;
+ mobskill_castend_pos(md->skilltimer,gettick(),md->bl.id, 0);
+ }
+
+ return 1;
+}
+
+
+/*==========================================
+ * Friendly Mob whose HP is decreasing by a nearby MOB is looked for.
+ *------------------------------------------
+ */
+int mob_getfriendhpltmaxrate_sub(struct block_list *bl,va_list ap)
+{
+ int rate;
+ struct mob_data **fr, *md, *mmd;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, mmd=va_arg(ap,struct mob_data *));
+
+ md=(struct mob_data *)bl;
+
+ if( mmd->bl.id == bl->id )
+ return 0;
+ rate=va_arg(ap,int);
+ fr=va_arg(ap,struct mob_data **);
+ if( md->hp < mob_db[md->class].max_hp*rate/100 )
+ (*fr)=md;
+ return 0;
+}
+struct mob_data *mob_getfriendhpltmaxrate(struct mob_data *md,int rate)
+{
+ struct mob_data *fr=NULL;
+ const int r=8;
+
+ nullpo_retr(NULL, md);
+
+ map_foreachinarea(mob_getfriendhpltmaxrate_sub, md->bl.m,
+ md->bl.x-r ,md->bl.y-r, md->bl.x+r, md->bl.y+r,
+ BL_MOB,md,rate,&fr);
+ return fr;
+}
+/*==========================================
+ * What a status state suits by nearby MOB is looked for.
+ *------------------------------------------
+ */
+int mob_getfriendstatus_sub(struct block_list *bl,va_list ap)
+{
+ int cond1,cond2;
+ struct mob_data **fr, *md, *mmd;
+ int flag=0;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, md=(struct mob_data *)bl);
+ nullpo_retr(0, mmd=va_arg(ap,struct mob_data *));
+
+ if( mmd->bl.id == bl->id )
+ return 0;
+ cond1=va_arg(ap,int);
+ cond2=va_arg(ap,int);
+ fr=va_arg(ap,struct mob_data **);
+ if( cond2==-1 ){
+ int j;
+ for(j=SC_STONE;j<=SC_BLIND && !flag;j++){
+ flag=(md->sc_data[j].timer!=-1 );
+ }
+ }else
+ flag=( md->sc_data[cond2].timer!=-1 );
+ if( flag^( cond1==MSC_FRIENDSTATUSOFF ) )
+ (*fr)=md;
+
+ return 0;
+}
+struct mob_data *mob_getfriendstatus(struct mob_data *md,int cond1,int cond2)
+{
+ struct mob_data *fr=NULL;
+ const int r=8;
+
+ nullpo_retr(0, md);
+
+ map_foreachinarea(mob_getfriendstatus_sub, md->bl.m,
+ md->bl.x-r ,md->bl.y-r, md->bl.x+r, md->bl.y+r,
+ BL_MOB,md,cond1,cond2,&fr);
+ return fr;
+}
+
+/*==========================================
+ * Skill use judging
+ *------------------------------------------
+ */
+int mobskill_use(struct mob_data *md,unsigned int tick,int event)
+{
+ struct mob_skill *ms;
+// struct block_list *target=NULL;
+ int i,max_hp;
+
+ nullpo_retr(0, md);
+ nullpo_retr(0, ms = mob_db[md->class].skill);
+
+ max_hp = battle_get_max_hp(&md->bl);
+
+ if(battle_config.mob_skill_use == 0 || md->skilltimer != -1)
+ return 0;
+
+ if(md->state.special_mob_ai)
+ return 0;
+
+ if(md->sc_data[SC_SELFDESTRUCTION].timer!=-1) //自爆中はスキルを使わない
+ return 0;
+
+ for(i=0;i<mob_db[md->class].maxskill;i++){
+ int c2=ms[i].cond2,flag=0;
+ struct mob_data *fmd=NULL;
+
+ // ディレイ中
+ if( DIFF_TICK(tick,md->skilldelay[i])<ms[i].delay )
+ continue;
+
+ // 状態判定
+ if( ms[i].state>=0 && ms[i].state!=md->state.skillstate )
+ continue;
+
+ // 条件判定
+ flag=(event==ms[i].cond1);
+ if(!flag){
+ switch( ms[i].cond1 ){
+ case MSC_ALWAYS:
+ flag=1; break;
+ case MSC_MYHPLTMAXRATE: // HP< maxhp%
+ flag=( md->hp < max_hp*c2/100 ); break;
+ case MSC_MYSTATUSON: // status[num] on
+ case MSC_MYSTATUSOFF: // status[num] off
+ if( ms[i].cond2==-1 ){
+ int j;
+ for(j=SC_STONE;j<=SC_BLIND && !flag;j++){
+ flag=(md->sc_data[j].timer!=-1 );
+ }
+ }else
+ flag=( md->sc_data[ms[i].cond2].timer!=-1 );
+ flag^=( ms[i].cond1==MSC_MYSTATUSOFF ); break;
+ case MSC_FRIENDHPLTMAXRATE: // friend HP < maxhp%
+ flag=(( fmd=mob_getfriendhpltmaxrate(md,ms[i].cond2) )!=NULL ); break;
+ case MSC_FRIENDSTATUSON: // friend status[num] on
+ case MSC_FRIENDSTATUSOFF: // friend status[num] off
+ flag=(( fmd=mob_getfriendstatus(md,ms[i].cond1,ms[i].cond2) )!=NULL ); break;
+ case MSC_SLAVELT: // slave < num
+ flag=( mob_countslave(md) < c2 ); break;
+ case MSC_ATTACKPCGT: // attack pc > num
+ flag=( mob_counttargeted(md,NULL,0) > c2 ); break;
+ case MSC_SLAVELE: // slave <= num
+ flag=( mob_countslave(md) <= c2 ); break;
+ case MSC_ATTACKPCGE: // attack pc >= num
+ flag=( mob_counttargeted(md,NULL,0) >= c2 ); break;
+ case MSC_SKILLUSED: // specificated skill used
+ flag=( (event&0xffff)==MSC_SKILLUSED && ((event>>16)==c2 || c2==0)); break;
+ }
+ }
+
+ // 確率判定
+ if( flag && rand()%10000 < ms[i].permillage ){
+
+ if( skill_get_inf(ms[i].skill_id)&2 ){
+ // 場所指定
+ struct block_list *bl = NULL;
+ int x=0,y=0;
+ if( ms[i].target<=MST_AROUND ){
+ bl= ((ms[i].target==MST_TARGET || ms[i].target==MST_AROUND5)? map_id2bl(md->target_id):
+ (ms[i].target==MST_FRIEND)? &fmd->bl : &md->bl);
+ if(bl!=NULL){
+ x=bl->x; y=bl->y;
+ }
+ }
+ if( x<=0 || y<=0 )
+ continue;
+ // 自分の周囲
+ if( ms[i].target>=MST_AROUND1 ){
+ int bx=x, by=y, i=0, c, m=bl->m, r=ms[i].target-MST_AROUND1;
+ do{
+ bx=x + rand()%(r*2+3) - r;
+ by=y + rand()%(r*2+3) - r;
+ }while( ( bx<=0 || by<=0 || bx>=map[m].xs || by>=map[m].ys ||
+ ((c=read_gat(m,bx,by))==1 || c==5) ) && (i++)<1000);
+ if(i<1000){
+ x=bx; y=by;
+ }
+ }
+ // 相手の周囲
+ if( ms[i].target>=MST_AROUND5 ){
+ int bx=x, by=y, i=0, c, m=bl->m, r=(ms[i].target-MST_AROUND5)+1;
+ do{
+ bx=x + rand()%(r*2+1) - r;
+ by=y + rand()%(r*2+1) - r;
+ }while( ( bx<=0 || by<=0 || bx>=map[m].xs || by>=map[m].ys ||
+ ((c=read_gat(m,bx,by))==1 || c==5) ) && (i++)<1000);
+ if(i<1000){
+ x=bx; y=by;
+ }
+ }
+ if(!mobskill_use_pos(md,x,y,i))
+ return 0;
+
+ }else{
+ // ID指定
+ if( ms[i].target<=MST_FRIEND ){
+ struct block_list *bl = NULL;
+ bl= ((ms[i].target==MST_TARGET)? map_id2bl(md->target_id):
+ (ms[i].target==MST_FRIEND)? &fmd->bl : &md->bl);
+ if(bl && !mobskill_use_id(md,bl,i))
+ return 0;
+ }
+ }
+ if(ms[i].emotion >= 0)
+ clif_emotion(&md->bl,ms[i].emotion);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+/*==========================================
+ * Skill use event processing
+ *------------------------------------------
+ */
+int mobskill_event(struct mob_data *md,int flag)
+{
+ nullpo_retr(0, md);
+
+ if(flag==-1 && mobskill_use(md,gettick(),MSC_CASTTARGETED))
+ return 1;
+ if( (flag&BF_SHORT) && mobskill_use(md,gettick(),MSC_CLOSEDATTACKED))
+ return 1;
+ if( (flag&BF_LONG) && mobskill_use(md,gettick(),MSC_LONGRANGEATTACKED))
+ return 1;
+ return 0;
+}
+/*==========================================
+ * Mobがエンペリウムなどの場合の判定
+ *------------------------------------------
+ */
+int mob_gvmobcheck(struct map_session_data *sd, struct block_list *bl)
+{
+ struct mob_data *md=NULL;
+
+ nullpo_retr(0,sd);
+ nullpo_retr(0,bl);
+
+ if(bl->type==BL_MOB && (md=(struct mob_data *)bl) &&
+ (md->class == 1288 || md->class == 1287 || md->class == 1286 || md->class == 1285))
+ {
+ struct guild_castle *gc=guild_mapname2gc(map[sd->bl.m].name);
+ struct guild *g=guild_search(sd->status.guild_id);
+
+ if(g == NULL && md->class == 1288)
+ return 0;//ギルド未加入ならダメージ無し
+ else if(gc != NULL && !map[sd->bl.m].flag.gvg)
+ return 0;//砦内でGvじゃないときはダメージなし
+ else if(g && gc != NULL && g->guild_id == gc->guild_id)
+ return 0;//自占領ギルドのエンペならダメージ無し
+ else if(g && guild_checkskill(g,GD_APPROVAL) <= 0 && md->class == 1288)
+ return 0;//正規ギルド承認がないとダメージ無し
+
+ }
+
+ return 1;
+}
+/*==========================================
+ * スキル用タイマー削除
+ *------------------------------------------
+ */
+int mobskill_deltimer(struct mob_data *md )
+{
+ nullpo_retr(0, md);
+
+ if( md->skilltimer!=-1 ){
+ if( skill_get_inf( md->skillid )&2 )
+ delete_timer( md->skilltimer, mobskill_castend_pos );
+ else
+ delete_timer( md->skilltimer, mobskill_castend_id );
+ md->skilltimer=-1;
+ }
+ return 0;
+}
+//
+// 初期化
+//
+/*==========================================
+ * Since un-setting [ mob ] up was used, it is an initial provisional value setup.
+ *------------------------------------------
+ */
+static int mob_makedummymobdb(int class)
+{
+ int i;
+
+ sprintf(mob_db[class].name,"mob%d",class);
+ sprintf(mob_db[class].jname,"mob%d",class);
+ mob_db[class].lv=1;
+ mob_db[class].max_hp=1000;
+ mob_db[class].max_sp=1;
+ mob_db[class].base_exp=2;
+ mob_db[class].job_exp=1;
+ mob_db[class].range=1;
+ mob_db[class].atk1=7;
+ mob_db[class].atk2=10;
+ mob_db[class].def=0;
+ mob_db[class].mdef=0;
+ mob_db[class].str=1;
+ mob_db[class].agi=1;
+ mob_db[class].vit=1;
+ mob_db[class].int_=1;
+ mob_db[class].dex=6;
+ mob_db[class].luk=2;
+ mob_db[class].range2=10;
+ mob_db[class].range3=10;
+ mob_db[class].size=0;
+ mob_db[class].race=0;
+ mob_db[class].element=0;
+ mob_db[class].mode=0;
+ mob_db[class].speed=300;
+ mob_db[class].adelay=1000;
+ mob_db[class].amotion=500;
+ mob_db[class].dmotion=500;
+ mob_db[class].dropitem[0].nameid=909; // Jellopy
+ mob_db[class].dropitem[0].p=1000;
+ for(i=1;i<8;i++){
+ mob_db[class].dropitem[i].nameid=0;
+ mob_db[class].dropitem[i].p=0;
+ }
+ // Item1,Item2
+ mob_db[class].mexp=0;
+ mob_db[class].mexpper=0;
+ for(i=0;i<3;i++){
+ mob_db[class].mvpitem[i].nameid=0;
+ mob_db[class].mvpitem[i].p=0;
+ }
+ for(i=0;i<MAX_RANDOMMONSTER;i++)
+ mob_db[class].summonper[i]=0;
+ return 0;
+}
+
+/*==========================================
+ * db/mob_db.txt reading
+ *------------------------------------------
+ */
+static int mob_readdb(void)
+{
+ FILE *fp;
+ char line[1024];
+ char *filename[]={ "db/mob_db.txt","db/mob_db2.txt" };
+ int i;
+
+ memset(mob_db,0,sizeof(mob_db));
+
+ for(i=0;i<2;i++){
+
+ fp=fopen(filename[i],"r");
+ if(fp==NULL){
+ if(i>0)
+ continue;
+ return -1;
+ }
+ while(fgets(line,1020,fp)){
+ int class,i;
+ char *str[55],*p,*np;
+
+ if(line[0] == '/' && line[1] == '/')
+ continue;
+
+ for(i=0,p=line;i<55;i++){
+ if((np=strchr(p,','))!=NULL){
+ str[i]=p;
+ *np=0;
+ p=np+1;
+ } else
+ str[i]=p;
+ }
+
+ class=atoi(str[0]);
+ if(class<=1000 || class>2000)
+ continue;
+
+ mob_db[class].view_class=class;
+ memcpy(mob_db[class].name,str[1],24);
+ memcpy(mob_db[class].jname,str[2],24);
+ mob_db[class].lv=atoi(str[3]);
+ mob_db[class].max_hp=atoi(str[4]);
+ mob_db[class].max_sp=atoi(str[5]);
+
+ mob_db[class].base_exp=atoi(str[6]);
+ if(mob_db[class].base_exp < 0)
+ mob_db[class].base_exp = 0;
+ else if(mob_db[class].base_exp > 0 && (mob_db[class].base_exp*battle_config.base_exp_rate/100 > 1000000000 ||
+ mob_db[class].base_exp*battle_config.base_exp_rate/100 < 0))
+ mob_db[class].base_exp=1000000000;
+ else
+ mob_db[class].base_exp*= battle_config.base_exp_rate/100;
+
+ mob_db[class].job_exp=atoi(str[7]);
+ if(mob_db[class].job_exp < 0)
+ mob_db[class].job_exp = 0;
+ else if(mob_db[class].job_exp > 0 && (mob_db[class].job_exp*battle_config.job_exp_rate/100 > 1000000000 ||
+ mob_db[class].job_exp*battle_config.job_exp_rate/100 < 0))
+ mob_db[class].job_exp=1000000000;
+ else
+ mob_db[class].job_exp*=battle_config.job_exp_rate/100;
+
+ mob_db[class].range=atoi(str[8]);
+ mob_db[class].atk1=atoi(str[9]);
+ mob_db[class].atk2=atoi(str[10]);
+ mob_db[class].def=atoi(str[11]);
+ mob_db[class].mdef=atoi(str[12]);
+ mob_db[class].str=atoi(str[13]);
+ mob_db[class].agi=atoi(str[14]);
+ mob_db[class].vit=atoi(str[15]);
+ mob_db[class].int_=atoi(str[16]);
+ mob_db[class].dex=atoi(str[17]);
+ mob_db[class].luk=atoi(str[18]);
+ mob_db[class].range2=atoi(str[19]);
+ mob_db[class].range3=atoi(str[20]);
+ mob_db[class].size=atoi(str[21]);
+ mob_db[class].race=atoi(str[22]);
+ mob_db[class].element=atoi(str[23]);
+ mob_db[class].mode=atoi(str[24]);
+ mob_db[class].speed=atoi(str[25]);
+ mob_db[class].adelay=atoi(str[26]);
+ mob_db[class].amotion=atoi(str[27]);
+ mob_db[class].dmotion=atoi(str[28]);
+
+ for(i=0;i<8;i++){
+ int rate = 0,type,ratemin,ratemax;
+ mob_db[class].dropitem[i].nameid=atoi(str[29+i*2]);
+ type = itemdb_type(mob_db[class].dropitem[i].nameid);
+ if (type == 0) { // Added [Valaris]
+ rate = battle_config.item_rate_heal;
+ ratemin = battle_config.item_drop_heal_min;
+ ratemax = battle_config.item_drop_heal_max;
+ }
+ else if (type == 2) {
+ rate = battle_config.item_rate_use;
+ ratemin = battle_config.item_drop_use_min;
+ ratemax = battle_config.item_drop_use_max; // End
+ }
+ else if (type == 4 || type == 5 || type == 8) { // Changed to include Pet Equip
+ rate = battle_config.item_rate_equip;
+ ratemin = battle_config.item_drop_equip_min;
+ ratemax = battle_config.item_drop_equip_max;
+ }
+ else if (type == 6) {
+ rate = battle_config.item_rate_card;
+ ratemin = battle_config.item_drop_card_min;
+ ratemax = battle_config.item_drop_card_max;
+ }
+ else {
+ rate = battle_config.item_rate_common;
+ ratemin = battle_config.item_drop_common_min;
+ ratemax = battle_config.item_drop_common_max;
+ }
+ rate = (rate / 100) * atoi(str[30+i*2]);
+ rate = (rate < ratemin)? ratemin: (rate > ratemax)? ratemax: rate;
+ mob_db[class].dropitem[i].p = rate;
+ }
+ // Item1,Item2
+ mob_db[class].mexp=atoi(str[45])*battle_config.mvp_exp_rate/100;
+ mob_db[class].mexpper=atoi(str[46]);
+ for(i=0;i<3;i++){
+ mob_db[class].mvpitem[i].nameid=atoi(str[47+i*2]);
+ mob_db[class].mvpitem[i].p=atoi(str[48+i*2])*battle_config.mvp_item_rate/100;
+ }
+ for(i=0;i<MAX_RANDOMMONSTER;i++)
+ mob_db[class].summonper[i]=0;
+ mob_db[class].maxskill=0;
+
+ mob_db[class].sex=0;
+ mob_db[class].hair=0;
+ mob_db[class].hair_color=0;
+ mob_db[class].weapon=0;
+ mob_db[class].shield=0;
+ mob_db[class].head_top=0;
+ mob_db[class].head_mid=0;
+ mob_db[class].head_buttom=0;
+ mob_db[class].clothes_color=0; //Add for player monster dye - Valaris
+ }
+ fclose(fp);
+ printf("read %s done\n",filename[i]);
+ }
+ return 0;
+}
+
+/*==========================================
+ * MOB display graphic change data reading
+ *------------------------------------------
+ */
+static int mob_readdb_mobavail(void)
+{
+ FILE *fp;
+ char line[1024];
+ int ln=0;
+ int class,j,k;
+ char *str[20],*p,*np;
+
+ if( (fp=fopen("db/mob_avail.txt","r"))==NULL ){
+ printf("can't read db/mob_avail.txt\n");
+ return -1;
+ }
+
+ while(fgets(line,1020,fp)){
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ memset(str,0,sizeof(str));
+
+ for(j=0,p=line;j<12;j++){
+ if((np=strchr(p,','))!=NULL){
+ str[j]=p;
+ *np=0;
+ p=np+1;
+ } else
+ str[j]=p;
+ }
+
+ if(str[0]==NULL)
+ continue;
+
+ class=atoi(str[0]);
+
+ if(class<=1000 || class>2000) // 値が異常なら処理しない。
+ continue;
+ k=atoi(str[1]);
+ if(k >= 0)
+ mob_db[class].view_class=k;
+
+ if((mob_db[class].view_class < 24) || (mob_db[class].view_class > 4000)) {
+ mob_db[class].sex=atoi(str[2]);
+ mob_db[class].hair=atoi(str[3]);
+ mob_db[class].hair_color=atoi(str[4]);
+ mob_db[class].weapon=atoi(str[5]);
+ mob_db[class].shield=atoi(str[6]);
+ mob_db[class].head_top=atoi(str[7]);
+ mob_db[class].head_mid=atoi(str[8]);
+ mob_db[class].head_buttom=atoi(str[9]);
+ mob_db[class].option=atoi(str[10])&~0x46;
+ mob_db[class].clothes_color=atoi(str[11]); // Monster player dye option - Valaris
+ }
+
+ else if(atoi(str[2]) > 0) mob_db[class].equip=atoi(str[2]); // mob equipment [Valaris]
+
+ ln++;
+ }
+ fclose(fp);
+ printf("read db/mob_avail.txt done (count=%d)\n",ln);
+ return 0;
+}
+
+/*==========================================
+ * Reading of random monster data
+ *------------------------------------------
+ */
+static int mob_read_randommonster(void)
+{
+ FILE *fp;
+ char line[1024];
+ char *str[10],*p;
+ int i,j;
+
+ const char* mobfile[] = {
+ "db/mob_branch.txt",
+ "db/mob_poring.txt",
+ "db/mob_boss.txt" };
+
+ for(i=0;i<MAX_RANDOMMONSTER;i++){
+ mob_db[0].summonper[i] = 1002; // 設定し忘れた場合はポリンが出るようにしておく
+ fp=fopen(mobfile[i],"r");
+ if(fp==NULL){
+ printf("can't read %s\n",mobfile[i]);
+ return -1;
+ }
+ while(fgets(line,1020,fp)){
+ int class,per;
+ if(line[0] == '/' && line[1] == '/')
+ continue;
+ memset(str,0,sizeof(str));
+ for(j=0,p=line;j<3 && p;j++){
+ str[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+
+ if(str[0]==NULL || str[2]==NULL)
+ continue;
+
+ class = atoi(str[0]);
+ per=atoi(str[2]);
+ if((class>1000 && class<=2000) || class==0)
+ mob_db[class].summonper[i]=per;
+ }
+ fclose(fp);
+ printf("read %s done\n",mobfile[i]);
+ }
+ return 0;
+}
+/*==========================================
+ * db/mob_skill_db.txt reading
+ *------------------------------------------
+ */
+static int mob_readskilldb(void)
+{
+ FILE *fp;
+ char line[1024];
+ int i;
+
+ const struct {
+ char str[32];
+ int id;
+ } cond1[] = {
+ { "always", MSC_ALWAYS },
+ { "myhpltmaxrate", MSC_MYHPLTMAXRATE },
+ { "friendhpltmaxrate",MSC_FRIENDHPLTMAXRATE },
+ { "mystatuson", MSC_MYSTATUSON },
+ { "mystatusoff", MSC_MYSTATUSOFF },
+ { "friendstatuson", MSC_FRIENDSTATUSON },
+ { "friendstatusoff", MSC_FRIENDSTATUSOFF },
+ { "attackpcgt", MSC_ATTACKPCGT },
+ { "attackpcge", MSC_ATTACKPCGE },
+ { "slavelt", MSC_SLAVELT },
+ { "slavele", MSC_SLAVELE },
+ { "closedattacked", MSC_CLOSEDATTACKED },
+ { "longrangeattacked",MSC_LONGRANGEATTACKED },
+ { "skillused", MSC_SKILLUSED },
+ { "casttargeted", MSC_CASTTARGETED },
+ }, cond2[] ={
+ { "anybad", -1 },
+ { "stone", SC_STONE },
+ { "freeze", SC_FREEZE },
+ { "stan", SC_STAN },
+ { "sleep", SC_SLEEP },
+ { "poison", SC_POISON },
+ { "curse", SC_CURSE },
+ { "silence", SC_SILENCE },
+ { "confusion", SC_CONFUSION },
+ { "blind", SC_BLIND },
+ { "hiding", SC_HIDING },
+ { "sight", SC_SIGHT },
+ }, state[] = {
+ { "any", -1 },
+ { "idle", MSS_IDLE },
+ { "walk", MSS_WALK },
+ { "attack", MSS_ATTACK },
+ { "dead", MSS_DEAD },
+ { "loot", MSS_LOOT },
+ { "chase", MSS_CHASE },
+ }, target[] = {
+ { "target", MST_TARGET },
+ { "self", MST_SELF },
+ { "friend", MST_FRIEND },
+ { "around5", MST_AROUND5 },
+ { "around6", MST_AROUND6 },
+ { "around7", MST_AROUND7 },
+ { "around8", MST_AROUND8 },
+ { "around1", MST_AROUND1 },
+ { "around2", MST_AROUND2 },
+ { "around3", MST_AROUND3 },
+ { "around4", MST_AROUND4 },
+ { "around", MST_AROUND },
+ };
+
+ int x;
+ char *filename[]={ "db/mob_skill_db.txt","db/mob_skill_db2.txt" };
+
+ for(x=0;x<2;x++){
+
+ fp=fopen(filename[x],"r");
+ if(fp==NULL){
+ if(x==0)
+ printf("can't read %s\n",filename[x]);
+ continue;
+ }
+ while(fgets(line,1020,fp)){
+ char *sp[20],*p;
+ int mob_id;
+ struct mob_skill *ms;
+ int j=0;
+
+ if(line[0] == '/' && line[1] == '/')
+ continue;
+
+ memset(sp,0,sizeof(sp));
+ for(i=0,p=line;i<18 && p;i++){
+ sp[i]=p;
+ if((p=strchr(p,','))!=NULL)
+ *p++=0;
+ }
+ if( (mob_id=atoi(sp[0]))<=0 )
+ continue;
+
+ if( strcmp(sp[1],"clear")==0 ){
+ memset(mob_db[mob_id].skill,0,sizeof(mob_db[mob_id].skill));
+ mob_db[mob_id].maxskill=0;
+ continue;
+ }
+
+ for(i=0;i<MAX_MOBSKILL;i++)
+ if( (ms=&mob_db[mob_id].skill[i])->skill_id == 0)
+ break;
+ if(i==MAX_MOBSKILL){
+ printf("mob_skill: readdb: too many skill ! [%s] in %d[%s]\n",
+ sp[1],mob_id,mob_db[mob_id].jname);
+ continue;
+ }
+
+ ms->state=atoi(sp[2]);
+ for(j=0;j<sizeof(state)/sizeof(state[0]);j++){
+ if( strcmp(sp[2],state[j].str)==0)
+ ms->state=state[j].id;
+ }
+ ms->skill_id=atoi(sp[3]);
+ ms->skill_lv=atoi(sp[4]);
+ ms->permillage=atoi(sp[5]);
+ ms->casttime=atoi(sp[6]);
+ ms->delay=atoi(sp[7]);
+ ms->cancel=atoi(sp[8]);
+ if( strcmp(sp[8],"yes")==0 ) ms->cancel=1;
+ ms->target=atoi(sp[9]);
+ for(j=0;j<sizeof(target)/sizeof(target[0]);j++){
+ if( strcmp(sp[9],target[j].str)==0)
+ ms->target=target[j].id;
+ }
+ ms->cond1=-1;
+ for(j=0;j<sizeof(cond1)/sizeof(cond1[0]);j++){
+ if( strcmp(sp[10],cond1[j].str)==0)
+ ms->cond1=cond1[j].id;
+ }
+ ms->cond2=atoi(sp[11]);
+ for(j=0;j<sizeof(cond2)/sizeof(cond2[0]);j++){
+ if( strcmp(sp[11],cond2[j].str)==0)
+ ms->cond2=cond2[j].id;
+ }
+ ms->val[0]=atoi(sp[12]);
+ ms->val[1]=atoi(sp[13]);
+ ms->val[2]=atoi(sp[14]);
+ ms->val[3]=atoi(sp[15]);
+ ms->val[4]=atoi(sp[16]);
+ if(sp[17] != NULL && strlen(sp[17])>2)
+ ms->emotion=atoi(sp[17]);
+ else
+ ms->emotion=-1;
+ mob_db[mob_id].maxskill=i+1;
+ }
+ fclose(fp);
+ printf("read %s done\n",filename[x]);
+ }
+ return 0;
+}
+
+void mob_reload(void)
+{
+ /*
+
+ <empty monster database>
+ mob_read();
+
+ */
+
+ do_init_mob();
+}
+
+#ifndef TXT_ONLY
+/*==========================================
+ * SQL reading
+ *------------------------------------------
+ */
+static int mob_read_sqldb(void)
+{
+ char line[1024];
+ int i,class,ln=0;
+ char *str[55],*p,*np;
+
+ memset(mob_db,0,sizeof(mob_db));
+
+ sprintf (tmp_sql, "SELECT * FROM `%s`",mob_db_db);
+ if(mysql_query(&mmysql_handle, tmp_sql) ) {
+ printf("DB server Error (select %s to Memory)- %s\n",mob_db_db,mysql_error(&mmysql_handle) );
+ }
+ sql_res = mysql_store_result(&mmysql_handle);
+ if (sql_res) {
+ while((sql_row = mysql_fetch_row(sql_res))){
+ sprintf(line,"%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s",
+ sql_row[0],sql_row[1],sql_row[2],sql_row[3],sql_row[4],
+ sql_row[5],sql_row[6],sql_row[7],sql_row[8],sql_row[9],
+ sql_row[10],sql_row[11],sql_row[12],sql_row[13],sql_row[14],
+ sql_row[15],sql_row[16],sql_row[17],sql_row[18],sql_row[19],
+ sql_row[20],sql_row[21],sql_row[22],sql_row[23],sql_row[24],
+ sql_row[25],sql_row[26],sql_row[27],sql_row[28],sql_row[29],
+ sql_row[30],sql_row[31],sql_row[32],sql_row[33],sql_row[34],
+ sql_row[35],sql_row[36],sql_row[37],sql_row[38],sql_row[39],
+ sql_row[40],sql_row[41],sql_row[42],sql_row[43],sql_row[44],
+ sql_row[45],sql_row[46],sql_row[47],sql_row[48],sql_row[49],
+ sql_row[50],sql_row[51],sql_row[52]);
+
+ for(i=0,p=line;i<55;i++){
+ if((np=strchr(p,','))!=NULL){
+ str[i]=p;
+ *np=0;
+ p=np+1;
+ } else
+ str[i]=p;
+ }
+
+ class=atoi(str[0]);
+ if(class<=1000 || class>2000)
+ continue;
+
+ ln++;
+
+ mob_db[class].view_class=class;
+ memcpy(mob_db[class].name,str[1],24);
+ memcpy(mob_db[class].jname,str[2],24);
+ mob_db[class].lv=atoi(str[3]);
+ mob_db[class].max_hp=atoi(str[4]);
+ mob_db[class].max_sp=atoi(str[5]);
+ mob_db[class].base_exp=atoi(str[6])*
+ battle_config.base_exp_rate/100;
+ if(mob_db[class].base_exp <= 0)
+ mob_db[class].base_exp = 1;
+ mob_db[class].job_exp=atoi(str[7])*
+ battle_config.job_exp_rate/100;
+ if(mob_db[class].job_exp <= 0)
+ mob_db[class].job_exp = 1;
+ mob_db[class].range=atoi(str[8]);
+ mob_db[class].atk1=atoi(str[9]);
+ mob_db[class].atk2=atoi(str[10]);
+ mob_db[class].def=atoi(str[11]);
+ mob_db[class].mdef=atoi(str[12]);
+ mob_db[class].str=atoi(str[13]);
+ mob_db[class].agi=atoi(str[14]);
+ mob_db[class].vit=atoi(str[15]);
+ mob_db[class].int_=atoi(str[16]);
+ mob_db[class].dex=atoi(str[17]);
+ mob_db[class].luk=atoi(str[18]);
+ mob_db[class].range2=atoi(str[19]);
+ mob_db[class].range3=atoi(str[20]);
+ mob_db[class].size=atoi(str[21]);
+ mob_db[class].race=atoi(str[22]);
+ mob_db[class].element=atoi(str[23]);
+ mob_db[class].mode=atoi(str[24]);
+ mob_db[class].speed=atoi(str[25]);
+ mob_db[class].adelay=atoi(str[26]);
+ mob_db[class].amotion=atoi(str[27]);
+ mob_db[class].dmotion=atoi(str[28]);
+
+ for(i=0;i<8;i++){
+ int rate = 0,type,ratemin,ratemax;
+ mob_db[class].dropitem[i].nameid=atoi(str[29+i*2]);
+ type = itemdb_type(mob_db[class].dropitem[i].nameid);
+ if (type == 0) { // Added by Valaris
+ rate = battle_config.item_rate_heal;
+ ratemin = battle_config.item_drop_heal_min;
+ ratemax = battle_config.item_drop_heal_max;
+ }
+ else if (type == 2) {
+ rate = battle_config.item_rate_use;
+ ratemin = battle_config.item_drop_use_min;
+ ratemax = battle_config.item_drop_use_max; // End
+ }
+ else if (type == 4 || type == 5 || type == 8) { // Changed to include Pet Equip
+ rate = battle_config.item_rate_equip;
+ ratemin = battle_config.item_drop_equip_min;
+ ratemax = battle_config.item_drop_equip_max;
+ }
+ else if (type == 6) {
+ rate = battle_config.item_rate_card;
+ ratemin = battle_config.item_drop_card_min;
+ ratemax = battle_config.item_drop_card_max;
+ }
+ else {
+ rate = battle_config.item_rate_common;
+ ratemin = battle_config.item_drop_common_min;
+ ratemax = battle_config.item_drop_common_max;
+ }
+ rate = (rate / 100) * atoi(str[30+i*2]);
+ rate = (rate < ratemin)? ratemin: (rate > ratemax)? ratemax: rate;
+ mob_db[class].dropitem[i].p = rate;
+ }
+
+ mob_db[class].mexp=atoi(str[45])*battle_config.mvp_exp_rate/100;
+ mob_db[class].mexpper=atoi(str[46]);
+ for(i=0;i<3;i++){
+ mob_db[class].mvpitem[i].nameid=atoi(str[47+i*2]);
+ mob_db[class].mvpitem[i].p=atoi(str[48+i*2])*battle_config.mvp_item_rate/100;
+ }
+ for(i=0;i<MAX_RANDOMMONSTER;i++)
+ mob_db[class].summonper[i]=0;
+ mob_db[class].maxskill=0;
+
+ mob_db[class].sex=0;
+ mob_db[class].hair=0;
+ mob_db[class].hair_color=0;
+ mob_db[class].weapon=0;
+ mob_db[class].shield=0;
+ mob_db[class].head_top=0;
+ mob_db[class].head_mid=0;
+ mob_db[class].head_buttom=0;
+ }
+ mysql_free_result(sql_res);
+ printf("read %s done (count=%d)\n",mob_db_db,ln);
+ }
+ return 0;
+}
+
+#endif /* not TXT_ONLY */
+/*==========================================
+ * Circumference initialization of mob
+ *------------------------------------------
+ */
+int do_init_mob(void)
+{
+#ifndef TXT_ONLY
+ if(db_use_sqldbs)
+ mob_read_sqldb();
+ else
+#endif /* TXT_ONLY */
+ mob_readdb();
+
+ mob_readdb_mobavail();
+ mob_read_randommonster();
+ mob_readskilldb();
+
+ add_timer_func_list(mob_timer,"mob_timer");
+ add_timer_func_list(mob_delayspawn,"mob_delayspawn");
+ add_timer_func_list(mob_delay_item_drop,"mob_delay_item_drop");
+ add_timer_func_list(mob_delay_item_drop2,"mob_delay_item_drop2");
+ add_timer_func_list(mob_ai_hard,"mob_ai_hard");
+ add_timer_func_list(mob_ai_lazy,"mob_ai_lazy");
+ add_timer_func_list(mobskill_castend_id,"mobskill_castend_id");
+ add_timer_func_list(mobskill_castend_pos,"mobskill_castend_pos");
+ add_timer_func_list(mob_timer_delete,"mob_timer_delete");
+ add_timer_interval(gettick()+MIN_MOBTHINKTIME,mob_ai_hard,0,0,MIN_MOBTHINKTIME);
+ add_timer_interval(gettick()+MIN_MOBTHINKTIME*10,mob_ai_lazy,0,0,MIN_MOBTHINKTIME*10);
+
+ return 0;
+}
diff --git a/src/map/mob.h b/src/map/mob.h
new file mode 100644
index 000000000..2ec71d90c
--- /dev/null
+++ b/src/map/mob.h
@@ -0,0 +1,139 @@
+// $Id: mob.h,v 1.4 2004/09/25 05:32:18 MouseJstr Exp $
+#ifndef _MOB_H_
+#define _MOB_H_
+
+#define MAX_RANDOMMONSTER 3
+
+struct mob_skill {
+ short state;
+ short skill_id,skill_lv;
+ short permillage;
+ int casttime,delay;
+ short cancel;
+ short cond1,cond2;
+ short target;
+ int val[5];
+ short emotion;
+};
+
+struct mob_db {
+ char name[24],jname[24];
+ int lv;
+ int max_hp,max_sp;
+ int base_exp,job_exp;
+ int atk1,atk2;
+ int def,mdef;
+ int str,agi,vit,int_,dex,luk;
+ int range,range2,range3;
+ int size,race,element,mode;
+ int speed,adelay,amotion,dmotion;
+ int mexp,mexpper;
+ struct { int nameid,p; } dropitem[8];
+ struct { int nameid,p; } mvpitem[3];
+ int view_class,sex;
+ short hair,hair_color,weapon,shield,head_top,head_mid,head_buttom,option,clothes_color; // [Valaris]
+ int equip; // [Valaris]
+ int summonper[MAX_RANDOMMONSTER];
+ int maxskill;
+ struct mob_skill skill[MAX_MOBSKILL];
+};
+extern struct mob_db mob_db[];
+
+enum {
+ MST_TARGET = 0,
+ MST_SELF = 1,
+ MST_FRIEND = 2,
+ MST_AROUND5 = 3,
+ MST_AROUND6 = 4,
+ MST_AROUND7 = 5,
+ MST_AROUND8 = 6,
+ MST_AROUND1 = 7,
+ MST_AROUND2 = 8,
+ MST_AROUND3 = 9,
+ MST_AROUND4 = 10,
+ MST_AROUND = MST_AROUND4,
+
+ MSC_ALWAYS = 0x0000,
+ MSC_MYHPLTMAXRATE = 0x0001,
+ MSC_FRIENDHPLTMAXRATE= 0x0010,
+ MSC_MYSTATUSON = 0x0020,
+ MSC_MYSTATUSOFF = 0x0021,
+ MSC_FRIENDSTATUSON = 0x0030,
+ MSC_FRIENDSTATUSOFF = 0x0031,
+
+ MSC_ATTACKPCGT = 0x0100,
+ MSC_ATTACKPCGE = 0x0101,
+ MSC_SLAVELT = 0x0110,
+ MSC_SLAVELE = 0x0111,
+ MSC_CLOSEDATTACKED = 0x1000,
+ MSC_LONGRANGEATTACKED= 0x1001,
+ MSC_SKILLUSED = 0x1010,
+ MSC_CASTTARGETED = 0x1011,
+};
+
+enum {
+ MSS_IDLE, // 待機
+ MSS_WALK, // 移動
+ MSS_ATTACK, // 攻撃
+ MSS_DEAD, // 死亡
+ MSS_LOOT, // ルート
+ MSS_CHASE, // 突撃
+};
+
+int mobdb_searchname(const char *str);
+int mobdb_checkid(const int id);
+int mob_once_spawn(struct map_session_data *sd,char *mapname,
+ int x,int y,const char *mobname,int class,int amount,const char *event);
+int mob_once_spawn_area(struct map_session_data *sd,char *mapname,
+ int x0,int y0,int x1,int y1,
+ const char *mobname,int class,int amount,const char *event);
+
+int mob_spawn_guardian(struct map_session_data *sd,char *mapname, // Spawning Guardians [Valaris]
+ int x,int y,const char *mobname,int class,int amount,const char *event,int guardian); // Spawning Guardians [Valaris]
+
+
+int mob_walktoxy(struct mob_data *md,int x,int y,int easy);
+
+int mob_target(struct mob_data *md,struct block_list *bl,int dist);
+int mob_stop_walking(struct mob_data *md,int type);
+int mob_stopattack(struct mob_data *);
+int mob_spawn(int);
+int mob_damage(struct block_list *,struct mob_data*,int,int);
+int mob_changestate(struct mob_data *md,int state,int type);
+int mob_heal(struct mob_data*,int);
+int mob_exclusion_add(struct mob_data *md,int type,int id);
+int mob_exclusion_check(struct mob_data *md,struct map_session_data *sd);
+int mob_get_viewclass(int);
+int mob_get_sex(int);
+short mob_get_hair(int);
+short mob_get_hair_color(int);
+short mob_get_weapon(int);
+short mob_get_shield(int);
+short mob_get_head_top(int);
+short mob_get_head_mid(int);
+short mob_get_head_buttom(int);
+short mob_get_clothes_color(int); //player mob dye [Valaris]
+int mob_get_equip(int); // mob equip [Valaris]
+int do_init_mob(void);
+
+int mob_delete(struct mob_data *md);
+int mob_catch_delete(struct mob_data *md,int type);
+int mob_timer_delete(int tid, unsigned int tick, int id, int data);
+
+int mob_deleteslave(struct mob_data *md);
+
+int mob_counttargeted(struct mob_data *md,struct block_list *src,int target_lv);
+
+int mob_class_change(struct mob_data *md,int *value);
+int mob_warp(struct mob_data *md,int m,int x,int y,int type);
+
+int mobskill_use(struct mob_data *md,unsigned int tick,int event);
+int mobskill_event(struct mob_data *md,int flag);
+int mobskill_castend_id( int tid, unsigned int tick, int id,int data );
+int mobskill_castend_pos( int tid, unsigned int tick, int id,int data );
+int mob_summonslave(struct mob_data *md2,int *value,int amount,int flag);
+
+int mob_gvmobcheck(struct map_session_data *sd, struct block_list *bl);
+void mob_reload(void);
+
+#endif
diff --git a/src/map/npc.c b/src/map/npc.c
new file mode 100644
index 000000000..1c089a2c9
--- /dev/null
+++ b/src/map/npc.c
@@ -0,0 +1,2274 @@
+// $Id: npc.c,v 1.5 2004/09/25 05:32:18 MouseJstr Exp $
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+
+#include "db.h"
+#include "timer.h"
+#include "nullpo.h"
+#include "malloc.h"
+#include "map.h"
+#include "npc.h"
+#include "clif.h"
+#include "intif.h"
+#include "pc.h"
+#include "itemdb.h"
+#include "script.h"
+#include "mob.h"
+#include "pet.h"
+#include "battle.h"
+#include "skill.h"
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+
+
+struct npc_src_list {
+ struct npc_src_list * next;
+ struct npc_src_list * prev;
+ char name[4];
+} ;
+
+static struct npc_src_list *npc_src_first,*npc_src_last;
+static int npc_id=START_NPC_NUM;
+static int npc_warp,npc_shop,npc_script,npc_mob;
+
+int npc_get_new_npc_id(void){ return npc_id++; }
+
+static struct dbt *ev_db;
+static struct dbt *npcname_db;
+
+struct event_data {
+ struct npc_data *nd;
+ int pos;
+};
+static struct tm ev_tm_b; // 時計イベント用
+
+static int npc_walktimer(int,unsigned int,int,int); // [Valaris]
+static int npc_walktoxy_sub(struct npc_data *nd); // [Valaris]
+
+/*==========================================
+ * NPCの無効化/有効化
+ * npc_enable
+ * npc_enable_sub 有効時にOnTouchイベントを実行
+ *------------------------------------------
+ */
+int npc_enable_sub( struct block_list *bl, va_list ap )
+{
+ struct map_session_data *sd;
+ struct npc_data *nd;
+ char *name=(char *)aCalloc(50,sizeof(char));
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, nd=va_arg(ap,struct npc_data *));
+ if(bl->type == BL_PC && (sd=(struct map_session_data *)bl)){
+
+ if (nd->flag&1) // 無効化されている
+ return 1;
+
+ memcpy(name,nd->name,50);
+ if(sd->areanpc_id==nd->bl.id)
+ return 1;
+ sd->areanpc_id=nd->bl.id;
+ npc_event(sd,strcat(name,"::OnTouch"),0);
+ }
+ free(name);
+ return 0;
+}
+int npc_enable(const char *name,int flag)
+{
+ struct npc_data *nd=strdb_search(npcname_db,name);
+ if (nd==NULL)
+ return 0;
+
+ if (flag&1) { // 有効化
+ nd->flag&=~1;
+ clif_spawnnpc(nd);
+ }else if (flag&2){
+ nd->flag&=~1;
+ nd->option = 0x0000;
+ clif_changeoption(&nd->bl);
+ }else if (flag&4){
+ nd->flag|=1;
+ nd->option = 0x0002;
+ clif_changeoption(&nd->bl);
+ }else{ // 無効化
+ nd->flag|=1;
+ clif_clearchar(&nd->bl,0);
+ }
+ if(flag&3 && (nd->u.scr.xs > 0 || nd->u.scr.ys >0))
+ map_foreachinarea( npc_enable_sub,nd->bl.m,nd->bl.x-nd->u.scr.xs,nd->bl.y-nd->u.scr.ys,nd->bl.x+nd->u.scr.xs,nd->bl.y+nd->u.scr.ys,BL_PC,nd);
+
+ return 0;
+}
+
+/*==========================================
+ * NPCを名前で探す
+ *------------------------------------------
+ */
+struct npc_data* npc_name2id(const char *name)
+{
+ return strdb_search(npcname_db,name);
+}
+/*==========================================
+ * イベントキューのイベント処理
+ *------------------------------------------
+ */
+int npc_event_dequeue(struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+
+ sd->npc_id=0;
+ if (sd->eventqueue[0][0]) { // キューのイベント処理
+ char *name=(char *)aCalloc(50,sizeof(char));
+ int i;
+
+ memcpy(name,sd->eventqueue[0],50);
+ for(i=MAX_EVENTQUEUE-2;i>=0;i--)
+ memcpy(sd->eventqueue[i],sd->eventqueue[i+1],50);
+ add_timer(gettick()+100,npc_event_timer,sd->bl.id,(int)name);
+ }
+ return 0;
+}
+
+int npc_delete(struct npc_data *nd)
+{
+ nullpo_retr(1, nd);
+
+ if(nd->bl.prev == NULL)
+ return 1;
+
+ clif_clearchar_area(&nd->bl,1);
+ map_delblock(&nd->bl);
+ return 0;
+}
+
+/*==========================================
+ * イベントの遅延実行
+ *------------------------------------------
+ */
+int npc_event_timer(int tid,unsigned int tick,int id,int data)
+{
+ struct map_session_data *sd=map_id2sd(id);
+ if (sd==NULL)
+ return 0;
+
+ npc_event(sd,(const char *)data,0);
+ free((void*)data);
+ return 0;
+}
+
+int npc_timer_event(const char *eventname) // Added by RoVeRT
+{
+ struct event_data *ev=strdb_search(ev_db,eventname);
+ struct npc_data *nd;
+// int xs,ys;
+
+ if((ev==NULL || (nd=ev->nd)==NULL)){
+ printf("npc_event: event not found [%s]\n",eventname);
+ return 0;
+ }
+
+ run_script(nd->u.scr.script,ev->pos,nd->bl.id,nd->bl.id);
+
+ return 0;
+}
+/*
+int npc_timer_sub_sub(void *key,void *data,va_list ap) // Added by RoVeRT
+{
+ char *p=(char *)key;
+ struct event_data *ev=(struct event_data *)data;
+ int *c=va_arg(ap,int *);
+ int tick=0,ctick=gettick();
+ char temp[10];
+ char event[100];
+
+ if(ev->nd->bl.id==(int)*c && (p=strchr(p,':')) && p && strncasecmp("::OnTimer",p,8)==0 ){
+ sscanf(&p[9],"%s",temp);
+ tick=atoi(temp);
+
+ strcpy( event, ev->nd->name);
+ strcat( event, p);
+
+ if (ctick >= ev->nd->lastaction && ctick - ev->nd->timer >= tick) {
+ npc_timer_event(event);
+ ev->nd->lastaction = ctick;
+ }
+ }
+ return 0;
+}
+
+int npc_timer_sub(void *key,void *data,va_list ap) // Added by RoVeRT
+{
+ struct npc_data *nd=(struct npc_data*)data;
+
+ if(nd->timer == -1)
+ return 0;
+
+ strdb_foreach(ev_db,npc_timer_sub_sub,&nd->bl.id);
+
+ return 0;
+}
+
+int npc_timer(int tid,unsigned int tick,int id,int data) // Added by RoVeRT
+{
+ strdb_foreach(npcname_db,npc_timer_sub);
+
+ free((void*)data);
+ return 0;
+}*/
+/*==========================================
+ * イベント用ラベルのエクスポート
+ * npc_parse_script->strdb_foreachから呼ばれる
+ *------------------------------------------
+ */
+int npc_event_export(void *key,void *data,va_list ap)
+{
+ char *lname=(char *)key;
+ int pos=(int)data;
+ struct npc_data *nd=va_arg(ap,struct npc_data *);
+
+ if ((lname[0]=='O' || lname[0]=='o')&&(lname[1]=='N' || lname[1]=='n')) {
+ struct event_data *ev;
+ char *buf;
+ char *p=strchr(lname,':');
+ // エクスポートされる
+ ev=calloc(sizeof(struct event_data), 1);
+ buf=calloc(50, 1);
+ if (ev==NULL || buf==NULL) {
+ printf("npc_event_export: out of memory !\n");
+ exit(1);
+ }else if (p==NULL || (p-lname)>24) {
+ printf("npc_event_export: label name error !\n");
+ exit(1);
+ }else{
+ ev->nd=nd;
+ ev->pos=pos;
+ *p='\0';
+ sprintf(buf,"%s::%s",nd->exname,lname);
+ *p=':';
+ strdb_insert(ev_db,buf,ev);
+// if (battle_config.etc_log)
+// printf("npc_event_export: export [%s]\n",buf);
+ }
+ }
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*==========================================
+ * 全てのNPCのOn*イベント実行
+ *------------------------------------------
+ */
+int npc_event_doall_sub(void *key,void *data,va_list ap)
+{
+ char *p=(char *)key;
+ struct event_data *ev;
+ int *c;
+ const char *name;
+
+ nullpo_retr(0, ev=(struct event_data *)data);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, c=va_arg(ap,int *));
+
+ name=va_arg(ap,const char *);
+
+ if( (p=strchr(p,':')) && p && strcmpi(name,p)==0 ){
+ run_script(ev->nd->u.scr.script,ev->pos,0,ev->nd->bl.id);
+ (*c)++;
+ }
+
+ return 0;
+}
+int npc_event_doall(const char *name)
+{
+ int c=0;
+ char buf[64]="::";
+
+ strncpy(buf+2,name,62);
+ strdb_foreach(ev_db,npc_event_doall_sub,&c,buf);
+ return c;
+}
+
+int npc_event_do_sub(void *key,void *data,va_list ap)
+{
+ char *p=(char *)key;
+ struct event_data *ev;
+ int *c;
+ const char *name;
+
+ nullpo_retr(0, ev=(struct event_data *)data);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, c=va_arg(ap,int *));
+
+ name=va_arg(ap,const char *);
+
+ if (p && strcmpi(name,p)==0 ) {
+ run_script(ev->nd->u.scr.script,ev->pos,0,ev->nd->bl.id);
+ (*c)++;
+ }
+
+ return 0;
+}
+int npc_event_do(const char *name)
+{
+ int c=0;
+
+ if (*name==':' && name[1]==':') {
+ return npc_event_doall(name+2);
+ }
+
+ strdb_foreach(ev_db,npc_event_do_sub,&c,name);
+ return c;
+}
+
+/*==========================================
+ * 時計イベント実行
+ *------------------------------------------
+ */
+int npc_event_do_clock(int tid,unsigned int tick,int id,int data)
+{
+ time_t timer;
+ struct tm *t;
+ char buf[64];
+ int c=0;
+
+ time(&timer);
+ t=localtime(&timer);
+
+ if (t->tm_min != ev_tm_b.tm_min ) {
+ sprintf(buf,"OnMinute%02d",t->tm_min);
+ c+=npc_event_doall(buf);
+ sprintf(buf,"OnClock%02d%02d",t->tm_hour,t->tm_min);
+ c+=npc_event_doall(buf);
+ }
+ if (t->tm_hour!= ev_tm_b.tm_hour) {
+ sprintf(buf,"OnHour%02d",t->tm_hour);
+ c+=npc_event_doall(buf);
+ }
+ if (t->tm_mday!= ev_tm_b.tm_mday) {
+ sprintf(buf,"OnDay%02d%02d",t->tm_mon+1,t->tm_mday);
+ c+=npc_event_doall(buf);
+ }
+ memcpy(&ev_tm_b,t,sizeof(ev_tm_b));
+ return c;
+}
+/*==========================================
+ * OnInitイベント実行(&時計イベント開始)
+ *------------------------------------------
+ */
+int npc_event_do_oninit(void)
+{
+ int c = npc_event_doall("OnInit");
+ printf("npc: OnInit Event done. (%d npc)\n",c);
+
+ add_timer_interval(gettick()+100,
+ npc_event_do_clock,0,0,1000);
+
+ return 0;
+}
+/*==========================================
+ * OnTimer NPC event - by RoVeRT
+ *------------------------------------------
+ */
+int npc_addeventtimer(struct npc_data *nd,int tick,const char *name)
+{
+ int i;
+ for(i=0;i<MAX_EVENTTIMER;i++)
+ if( nd->eventtimer[i]==-1 )
+ break;
+ if(i<MAX_EVENTTIMER){
+ char *evname=malloc(24);
+ if(evname==NULL){
+ printf("npc_addeventtimer: out of memory !\n");exit(1);
+ }
+ memcpy(evname,name,24);
+ nd->eventtimer[i]=add_timer(gettick()+tick,
+ npc_event_timer,nd->bl.id,(int)evname);
+ }else
+ printf("npc_addtimer: event timer is full !\n");
+
+ return 0;
+}
+
+int npc_deleventtimer(struct npc_data *nd,const char *name)
+{
+ int i;
+ for(i=0;i<MAX_EVENTTIMER;i++)
+ if( nd->eventtimer[i]!=-1 && strcmp(
+ (char *)(get_timer(nd->eventtimer[i])->data), name)==0 ){
+ delete_timer(nd->eventtimer[i],npc_event_timer);
+ nd->eventtimer[i]=-1;
+ break;
+ }
+
+ return 0;
+}
+
+int npc_cleareventtimer(struct npc_data *nd)
+{
+ int i;
+ for(i=0;i<MAX_EVENTTIMER;i++)
+ if( nd->eventtimer[i]!=-1 ){
+ delete_timer(nd->eventtimer[i],npc_event_timer);
+ nd->eventtimer[i]=-1;
+ }
+
+ return 0;
+}
+
+int npc_do_ontimer_sub(void *key,void *data,va_list ap)
+{
+ char *p=(char *)key;
+ struct event_data *ev=(struct event_data *)data;
+ int *c=va_arg(ap,int *);
+// struct map_session_data *sd=va_arg(ap,struct map_session_data *);
+ int option=va_arg(ap,int);
+ int tick=0;
+ char temp[10];
+ char event[50];
+
+ if(ev->nd->bl.id==(int)*c && (p=strchr(p,':')) && p && strnicmp("::OnTimer",p,8)==0 ){
+ sscanf(&p[9],"%s",temp);
+ tick=atoi(temp);
+
+ strcpy( event, ev->nd->name);
+ strcat( event, p);
+
+ if (option!=0) {
+ npc_addeventtimer(ev->nd,tick,event);
+ } else {
+ npc_deleventtimer(ev->nd,event);
+ }
+ }
+ return 0;
+}
+int npc_do_ontimer(int npc_id, struct map_session_data *sd, int option)
+{
+ strdb_foreach(ev_db,npc_do_ontimer_sub,&npc_id,sd,option);
+ return 0;
+}
+/*==========================================
+ * タイマーイベント用ラベルの取り込み
+ * npc_parse_script->strdb_foreachから呼ばれる
+ *------------------------------------------
+ */
+int npc_timerevent_import(void *key,void *data,va_list ap)
+{
+ char *lname=(char *)key;
+ int pos=(int)data;
+ struct npc_data *nd=va_arg(ap,struct npc_data *);
+ int t=0,i=0;
+
+ if(sscanf(lname,"OnTimer%d%n",&t,&i)==1 && lname[i]==':') {
+ // タイマーイベント
+ struct npc_timerevent_list *te=nd->u.scr.timer_event;
+ int j,i=nd->u.scr.timeramount;
+ if(te==NULL) te=malloc(sizeof(struct npc_timerevent_list));
+ else te=realloc( te, sizeof(struct npc_timerevent_list) * (i+1) );
+ if(te==NULL){
+ printf("npc_timerevent_import: out of memory !\n");
+ exit(1);
+ }
+ for(j=0;j<i;j++){
+ if(te[j].timer>t){
+ memmove(te+j+1,te+j,sizeof(struct npc_timerevent_list)*(i-j));
+ break;
+ }
+ }
+ te[j].timer=t;
+ te[j].pos=pos;
+ nd->u.scr.timer_event=te;
+ nd->u.scr.timeramount=i+1;
+ }
+ return 0;
+}
+/*==========================================
+ * タイマーイベント実行
+ *------------------------------------------
+ */
+int npc_timerevent(int tid,unsigned int tick,int id,int data)
+{
+ int next,t;
+ struct npc_data* nd=(struct npc_data *)map_id2bl(id);
+ struct npc_timerevent_list *te;
+ if( nd==NULL || nd->u.scr.nexttimer<0 ){
+ printf("npc_timerevent: ??\n");
+ return 0;
+ }
+ nd->u.scr.timertick=tick;
+ te=nd->u.scr.timer_event+ nd->u.scr.nexttimer;
+ nd->u.scr.timerid = -1;
+
+ t = nd->u.scr.timer+=data;
+ nd->u.scr.nexttimer++;
+ if( nd->u.scr.timeramount>nd->u.scr.nexttimer ){
+ next= nd->u.scr.timer_event[ nd->u.scr.nexttimer ].timer - t;
+ nd->u.scr.timerid = add_timer(tick+next,npc_timerevent,id,next);
+ }
+
+ run_script(nd->u.scr.script,te->pos,0,nd->bl.id);
+ return 0;
+}
+/*==========================================
+ * タイマーイベント開始
+ *------------------------------------------
+ */
+int npc_timerevent_start(struct npc_data *nd)
+{
+ int j,n, next;
+
+ nullpo_retr(0, nd);
+
+ n=nd->u.scr.timeramount;
+ if( nd->u.scr.nexttimer>=0 || n==0 )
+ return 0;
+
+ for(j=0;j<n;j++){
+ if( nd->u.scr.timer_event[j].timer > nd->u.scr.timer )
+ break;
+ }
+ nd->u.scr.nexttimer=j;
+ nd->u.scr.timertick=gettick();
+
+ if(j>=n)
+ return 0;
+
+ next = nd->u.scr.timer_event[j].timer - nd->u.scr.timer;
+ nd->u.scr.timerid = add_timer(gettick()+next,npc_timerevent,nd->bl.id,next);
+ return 0;
+}
+/*==========================================
+ * タイマーイベント終了
+ *------------------------------------------
+ */
+int npc_timerevent_stop(struct npc_data *nd)
+{
+ nullpo_retr(0, nd);
+
+ if( nd->u.scr.nexttimer>=0 ){
+ nd->u.scr.nexttimer = -1;
+ nd->u.scr.timer += (int)(gettick() - nd->u.scr.timertick);
+ if(nd->u.scr.timerid!=-1)
+ delete_timer(nd->u.scr.timerid,npc_timerevent);
+ nd->u.scr.timerid = -1;
+ }
+ return 0;
+}
+/*==========================================
+ * タイマー値の所得
+ *------------------------------------------
+ */
+int npc_gettimerevent_tick(struct npc_data *nd)
+{
+ int tick;
+
+ nullpo_retr(0, nd);
+
+ tick=nd->u.scr.timer;
+
+ if( nd->u.scr.nexttimer>=0 )
+ tick += (int)(gettick() - nd->u.scr.timertick);
+ return tick;
+}
+/*==========================================
+ * タイマー値の設定
+ *------------------------------------------
+ */
+int npc_settimerevent_tick(struct npc_data *nd,int newtimer)
+{
+ int flag;
+
+ nullpo_retr(0, nd);
+
+ flag= nd->u.scr.nexttimer;
+
+ npc_timerevent_stop(nd);
+ nd->u.scr.timer=newtimer;
+ if(flag>=0)
+ npc_timerevent_start(nd);
+ return 0;
+}
+
+/*==========================================
+ * イベント型のNPC処理
+ *------------------------------------------
+ */
+int npc_event(struct map_session_data *sd,const char *eventname,int mob_kill)
+{
+ struct event_data *ev=strdb_search(ev_db,eventname);
+ struct npc_data *nd;
+ int xs,ys;
+ char mobevent[100];
+
+ if( sd == NULL ){
+ printf("npc_event nullpo?\n");
+ }
+
+ if(ev==NULL && eventname && strcmp(((eventname)+strlen(eventname)-9),"::OnTouch") == 0)
+ return 1;
+
+ if(ev==NULL || (nd=ev->nd)==NULL){
+ if(mob_kill && (ev==NULL || (nd=ev->nd)==NULL)){
+ strcpy( mobevent, eventname);
+ strcat( mobevent, "::OnMyMobDead");
+ ev=strdb_search(ev_db,mobevent);
+ if (ev==NULL || (nd=ev->nd)==NULL) {
+ if (strnicmp(eventname,"GM_MONSTER",10)!=0)
+ printf("npc_event: event not found [%s]\n",mobevent);
+ return 0;
+ }
+ }
+ else {
+ if(battle_config.error_log)
+ printf("npc_event: event not found [%s]\n",eventname);
+ return 0;
+ }
+ }
+
+ xs=nd->u.scr.xs;
+ ys=nd->u.scr.ys;
+ if (xs>=0 && ys>=0 ) {
+ if (nd->bl.m != sd->bl.m )
+ return 1;
+ if ( xs>0 && (sd->bl.x<nd->bl.x-xs/2 || nd->bl.x+xs/2<sd->bl.x) )
+ return 1;
+ if ( ys>0 && (sd->bl.y<nd->bl.y-ys/2 || nd->bl.y+ys/2<sd->bl.y) )
+ return 1;
+ }
+
+ if ( sd->npc_id!=0) {
+// if (battle_config.error_log)
+// printf("npc_event: npc_id != 0\n");
+ int i;
+ for(i=0;i<MAX_EVENTQUEUE;i++)
+ if (!sd->eventqueue[i][0])
+ break;
+ if (i==MAX_EVENTQUEUE) {
+ if (battle_config.error_log)
+ printf("npc_event: event queue is full !\n");
+ }else{
+// if (battle_config.etc_log)
+// printf("npc_event: enqueue\n");
+ memcpy(sd->eventqueue[i],eventname,50);
+ }
+ return 1;
+ }
+ if (nd->flag&1) { // 無効化されている
+ npc_event_dequeue(sd);
+ return 0;
+ }
+
+ sd->npc_id=nd->bl.id;
+ sd->npc_pos=run_script(nd->u.scr.script,ev->pos,sd->bl.id,nd->bl.id);
+ return 0;
+}
+
+
+int npc_command_sub(void *key,void *data,va_list ap)
+{
+ char *p=(char *)key;
+ struct event_data *ev=(struct event_data *)data;
+ char *npcname=va_arg(ap,char *);
+ char *command=va_arg(ap,char *);
+ char temp[100];
+
+ if(strcmp(ev->nd->name,npcname)==0 && (p=strchr(p,':')) && p && strnicmp("::OnCommand",p,10)==0 ){
+ sscanf(&p[11],"%s",temp);
+
+ if (strcmp(command,temp)==0)
+ run_script(ev->nd->u.scr.script,ev->pos,0,ev->nd->bl.id);
+ }
+
+ return 0;
+}
+
+int npc_command(struct map_session_data *sd,char *npcname,char *command)
+{
+ strdb_foreach(ev_db,npc_command_sub,npcname,command);
+
+ return 0;
+}
+/*==========================================
+ * 接触型のNPC処理
+ *------------------------------------------
+ */
+int npc_touch_areanpc(struct map_session_data *sd,int m,int x,int y)
+{
+ int i,f=1;
+ int xs,ys;
+
+ nullpo_retr(1, sd);
+
+ if(sd->npc_id)
+ return 1;
+
+ for(i=0;i<map[m].npc_num;i++) {
+ if (map[m].npc[i]->flag&1) { // 無効化されている
+ f=0;
+ continue;
+ }
+
+ switch(map[m].npc[i]->bl.subtype) {
+ case WARP:
+ xs=map[m].npc[i]->u.warp.xs;
+ ys=map[m].npc[i]->u.warp.ys;
+ break;
+ case SCRIPT:
+ xs=map[m].npc[i]->u.scr.xs;
+ ys=map[m].npc[i]->u.scr.ys;
+ break;
+ default:
+ continue;
+ }
+ if (x >= map[m].npc[i]->bl.x-xs/2 && x < map[m].npc[i]->bl.x-xs/2+xs &&
+ y >= map[m].npc[i]->bl.y-ys/2 && y < map[m].npc[i]->bl.y-ys/2+ys)
+ break;
+ }
+ if (i==map[m].npc_num) {
+ if (f) {
+ if (battle_config.error_log)
+ printf("npc_touch_areanpc : some bug \n");
+ }
+ return 1;
+ }
+ switch(map[m].npc[i]->bl.subtype) {
+ case WARP:
+ skill_stop_dancing(&sd->bl,0);
+ pc_setpos(sd,map[m].npc[i]->u.warp.name,map[m].npc[i]->u.warp.x,map[m].npc[i]->u.warp.y,0);
+ break;
+ case SCRIPT:
+ {
+ char *name=(char *)aCalloc(50,sizeof(char));
+
+ memcpy(name,map[m].npc[i]->name,50);
+ if(sd->areanpc_id==map[m].npc[i]->bl.id)
+ return 1;
+ sd->areanpc_id=map[m].npc[i]->bl.id;
+ if(npc_event(sd,strcat(name,"::OnTouch"),0)>0)
+ npc_click(sd,map[m].npc[i]->bl.id);
+ free(name);
+ break;
+ }
+ }
+ return 0;
+}
+
+/*==========================================
+ * 近くかどうかの判定
+ *------------------------------------------
+ */
+int npc_checknear(struct map_session_data *sd,int id)
+{
+ struct npc_data *nd;
+
+ nullpo_retr(0, sd);
+
+ nd=(struct npc_data *)map_id2bl(id);
+ if (nd==NULL || nd->bl.type!=BL_NPC) {
+ if (battle_config.error_log)
+ printf("no such npc : %d\n",id);
+ return 1;
+ }
+
+ if (nd->class<0) // イベント系は常にOK
+ return 0;
+
+ // エリア判定
+ if (nd->bl.m!=sd->bl.m ||
+ nd->bl.x<sd->bl.x-AREA_SIZE-1 || nd->bl.x>sd->bl.x+AREA_SIZE+1 ||
+ nd->bl.y<sd->bl.y-AREA_SIZE-1 || nd->bl.y>sd->bl.y+AREA_SIZE+1)
+ return 1;
+
+ return 0;
+}
+
+/*==========================================
+ * クリック時のNPC処理
+ *------------------------------------------
+ */
+int npc_click(struct map_session_data *sd,int id)
+{
+ struct npc_data *nd;
+
+ nullpo_retr(1, sd);
+
+ if (sd->npc_id != 0) {
+ if (battle_config.error_log)
+ printf("npc_click: npc_id != 0\n");
+ return 1;
+ }
+
+ if (npc_checknear(sd,id))
+ return 1;
+
+ nd=(struct npc_data *)map_id2bl(id);
+
+ if (nd->flag&1) // 無効化されている
+ return 1;
+
+ sd->npc_id=id;
+ switch(nd->bl.subtype) {
+ case SHOP:
+ clif_npcbuysell(sd,id);
+ npc_event_dequeue(sd);
+ break;
+ case SCRIPT:
+ sd->npc_pos=run_script(nd->u.scr.script,0,sd->bl.id,id);
+ break;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int npc_scriptcont(struct map_session_data *sd,int id)
+{
+ struct npc_data *nd;
+
+ nullpo_retr(1, sd);
+
+ if (id!=sd->npc_id)
+ return 1;
+ if (npc_checknear(sd,id))
+ return 1;
+
+ nd=(struct npc_data *)map_id2bl(id);
+
+ sd->npc_pos=run_script(nd->u.scr.script,sd->npc_pos,sd->bl.id,id);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int npc_buysellsel(struct map_session_data *sd,int id,int type)
+{
+ struct npc_data *nd;
+
+ nullpo_retr(1, sd);
+
+ if (npc_checknear(sd,id))
+ return 1;
+
+ nd=(struct npc_data *)map_id2bl(id);
+ if (nd->bl.subtype!=SHOP) {
+ if (battle_config.error_log)
+ printf("no such shop npc : %d\n",id);
+ sd->npc_id=0;
+ return 1;
+ }
+ if (nd->flag&1) // 無効化されている
+ return 1;
+
+ sd->npc_shopid=id;
+ if (type==0) {
+ clif_buylist(sd,nd);
+ } else {
+ clif_selllist(sd);
+ }
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int npc_buylist(struct map_session_data *sd,int n,unsigned short *item_list)
+{
+ struct npc_data *nd;
+ double z;
+ int i,j,w,skill,itemamount=0,new=0;
+
+ nullpo_retr(3, sd);
+ nullpo_retr(3, item_list);
+
+ if (npc_checknear(sd,sd->npc_shopid))
+ return 3;
+
+ nd=(struct npc_data*)map_id2bl(sd->npc_shopid);
+ if (nd->bl.subtype!=SHOP)
+ return 3;
+
+ for(i=0,w=0,z=0;i<n;i++) {
+ for(j=0;nd->u.shop_item[j].nameid;j++) {
+ if (nd->u.shop_item[j].nameid==item_list[i*2+1])
+ break;
+ }
+ if (nd->u.shop_item[j].nameid==0)
+ return 3;
+
+ if (itemdb_value_notdc(nd->u.shop_item[j].nameid))
+ z+=(double)nd->u.shop_item[j].value * item_list[i*2];
+ else
+ z+=(double)pc_modifybuyvalue(sd,nd->u.shop_item[j].value) * item_list[i*2];
+ itemamount+=item_list[i*2];
+
+ switch(pc_checkadditem(sd,item_list[i*2+1],item_list[i*2])) {
+ case ADDITEM_EXIST:
+ break;
+ case ADDITEM_NEW:
+ new++;
+ break;
+ case ADDITEM_OVERAMOUNT:
+ return 2;
+ }
+
+ w+=itemdb_weight(item_list[i*2+1]) * item_list[i*2];
+ }
+ if (z > (double)sd->status.zeny)
+ return 1; // zeny不足
+ if (w+sd->weight > sd->max_weight)
+ return 2; // 重量超過
+ if (pc_inventoryblank(sd)<new)
+ return 3; // 種類数超過
+
+ pc_payzeny(sd,(int)z);
+ for(i=0;i<n;i++) {
+ struct item item_tmp;
+
+ memset(&item_tmp,0,sizeof(item_tmp));
+ item_tmp.nameid = item_list[i*2+1];
+ item_tmp.identify = 1; // npc販売アイテムは鑑定済み
+
+ pc_additem(sd,&item_tmp,item_list[i*2]);
+ }
+
+ //商人経験値
+/* if ((sd->status.class == 5) || (sd->status.class == 10) || (sd->status.class == 18)) {
+ z = z * pc_checkskill(sd,MC_DISCOUNT) / ((1 + 300 / itemamount) * 4000) * battle_config.shop_exp;
+ pc_gainexp(sd,0,z);
+ }*/
+ 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 (skill > 0) {
+ z = (log(z * (double)skill) * (double)battle_config.shop_exp/100.);
+ if (z < 1)
+ z = 1;
+ pc_gainexp(sd,0,(int)z);
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int npc_selllist(struct map_session_data *sd,int n,unsigned short *item_list)
+{
+ double z;
+ int i,skill,itemamount=0;
+
+ nullpo_retr(1, sd);
+ nullpo_retr(1, item_list);
+
+ if (npc_checknear(sd,sd->npc_shopid))
+ return 1;
+ for(i=0,z=0;i<n;i++) {
+ int nameid;
+ if (item_list[i*2]-2 <0 || item_list[i*2]-2 >=MAX_INVENTORY)
+ return 1;
+ nameid=sd->status.inventory[item_list[i*2]-2].nameid;
+ if (nameid == 0 ||
+ sd->status.inventory[item_list[i*2]-2].amount < item_list[i*2+1])
+ return 1;
+ if (itemdb_value_notoc(nameid))
+ z+=(double)itemdb_value_sell(nameid) * item_list[i*2+1];
+ else
+ z+=(double)pc_modifysellvalue(sd,itemdb_value_sell(nameid)) * item_list[i*2+1];
+ itemamount+=item_list[i*2+1];
+ }
+
+ if (z > MAX_ZENY) z = MAX_ZENY;
+ pc_getzeny(sd,(int)z);
+ for(i=0;i<n;i++) {
+ int item_id=item_list[i*2]-2;
+ if( sd->status.inventory[item_id].nameid>0 && sd->inventory_data[item_id] != NULL &&
+ sd->inventory_data[item_id]->type==7 && sd->status.inventory[item_id].amount>0 &&
+ sd->status.inventory[item_id].card[0] == (short)0xff00)
+ if(search_petDB_index(sd->status.inventory[item_id].nameid, PET_EGG) >= 0)
+ intif_delete_petdata((*(long *)(&sd->status.inventory[item_id].card[1])));
+ pc_delitem(sd,item_id,item_list[i*2+1],0);
+ }
+
+ //商人経験値
+/* if ((sd->status.class == 5) || (sd->status.class == 10) || (sd->status.class == 18)) {
+ z = z * pc_checkskill(sd,MC_OVERCHARGE) / ((1 + 500 / itemamount) * 4000) * battle_config.shop_exp ;
+ pc_gainexp(sd,0,z);
+ }*/
+ 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 (skill > 0) {
+ z = (log(z * (double)skill) * (double)battle_config.shop_exp/100.);
+ if (z < 1)
+ z = 1;
+ pc_gainexp(sd,0,(int)z);
+ }
+ }
+
+ return 0;
+
+}
+
+// [Valaris] NPC Walking
+
+/*==========================================
+ * Time calculation concerning one step next to npc
+ *------------------------------------------
+ */
+static int calc_next_walk_step(struct npc_data *nd)
+{
+ nullpo_retr(0, nd);
+
+ if(nd->walkpath.path_pos>=nd->walkpath.path_len)
+ return -1;
+ if(nd->walkpath.path[nd->walkpath.path_pos]&1)
+ return battle_get_speed(&nd->bl)*14/10;
+ return battle_get_speed(&nd->bl);
+}
+
+
+/*==========================================
+ * npc Walk processing
+ *------------------------------------------
+ */
+static int npc_walk(struct npc_data *nd,unsigned int tick,int data)
+{
+ int moveblock;
+ int i,ctype;
+ static int dirx[8]={0,-1,-1,-1,0,1,1,1};
+ static int diry[8]={1,1,0,-1,-1,-1,0,1};
+ int x,y,dx,dy;
+
+ nullpo_retr(0, nd);
+
+ nd->state.state=MS_IDLE;
+ if(nd->walkpath.path_pos>=nd->walkpath.path_len || nd->walkpath.path_pos!=data)
+ return 0;
+
+ nd->walkpath.path_half ^= 1;
+ if(nd->walkpath.path_half==0){
+ nd->walkpath.path_pos++;
+ if(nd->state.change_walk_target){
+ npc_walktoxy_sub(nd);
+ return 0;
+ }
+ }
+ else {
+ if(nd->walkpath.path[nd->walkpath.path_pos]>=8)
+ return 1;
+
+ x = nd->bl.x;
+ y = nd->bl.y;
+ ctype = map_getcell(nd->bl.m,x,y);
+ if(ctype == 1 || ctype == 5) {
+ npc_stop_walking(nd,1);
+ return 0;
+ }
+ nd->dir=nd->walkpath.path[nd->walkpath.path_pos];
+ dx = dirx[nd->dir];
+ dy = diry[nd->dir];
+
+ ctype = map_getcell(nd->bl.m,x+dx,y+dy);
+ if(ctype == 1 || ctype == 5) {
+ npc_walktoxy_sub(nd);
+ return 0;
+ }
+
+ moveblock = ( x/BLOCK_SIZE != (x+dx)/BLOCK_SIZE || y/BLOCK_SIZE != (y+dy)/BLOCK_SIZE);
+
+ nd->state.state=MS_WALK;
+ map_foreachinmovearea(clif_npcoutsight,nd->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,BL_PC,nd);
+
+ x += dx;
+ y += dy;
+
+ if(moveblock) map_delblock(&nd->bl);
+ nd->bl.x = x;
+ nd->bl.y = y;
+ if(moveblock) map_addblock(&nd->bl);
+
+ map_foreachinmovearea(clif_npcinsight,nd->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,-dx,-dy,BL_PC,nd);
+ nd->state.state=MS_IDLE;
+ }
+ if((i=calc_next_walk_step(nd))>0){
+ i = i>>1;
+ if(i < 1 && nd->walkpath.path_half == 0)
+ i = 1;
+ nd->walktimer=add_timer(tick+i,npc_walktimer,nd->bl.id,nd->walkpath.path_pos);
+ nd->state.state=MS_WALK;
+
+ if(nd->walkpath.path_pos>=nd->walkpath.path_len)
+ clif_fixnpcpos(nd); // When npc stops, retransmission current of a position.
+
+ }
+ return 0;
+}
+
+int npc_changestate(struct npc_data *nd,int state,int type)
+{
+ int i;
+
+ nullpo_retr(0, nd);
+
+ if(nd->walktimer != -1)
+ delete_timer(nd->walktimer,npc_walktimer);
+ nd->walktimer=-1;
+ nd->state.state=state;
+
+ switch(state){
+ case MS_WALK:
+ if((i=calc_next_walk_step(nd))>0){
+ i = i>>2;
+ nd->walktimer=add_timer(gettick()+i,npc_walktimer,nd->bl.id,0);
+ }
+ else
+ nd->state.state=MS_IDLE;
+ break;
+ case MS_DELAY:
+ nd->walktimer=add_timer(gettick()+type,npc_walktimer,nd->bl.id,0);
+ break;
+
+ }
+
+ return 0;
+}
+
+static int npc_walktimer(int tid,unsigned int tick,int id,int data)
+{
+ struct npc_data *nd;
+
+ nd=(struct npc_data*)map_id2bl(id);
+ if(nd == NULL || nd->bl.type != BL_NPC)
+ return 1;
+
+ if(nd->walktimer != tid){
+ return 0;
+ }
+
+ nd->walktimer=-1;
+
+ if(nd->bl.prev == NULL)
+ return 1;
+
+ switch(nd->state.state){
+ case MS_WALK:
+ npc_walk(nd,tick,data);
+ break;
+ case MS_DELAY:
+ npc_changestate(nd,MS_IDLE,0);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+static int npc_walktoxy_sub(struct npc_data *nd)
+{
+ struct walkpath_data wpd;
+
+ nullpo_retr(0, nd);
+
+ if(path_search(&wpd,nd->bl.m,nd->bl.x,nd->bl.y,nd->to_x,nd->to_y,nd->state.walk_easy))
+ return 1;
+ memcpy(&nd->walkpath,&wpd,sizeof(wpd));
+
+ nd->state.change_walk_target=0;
+ npc_changestate(nd,MS_WALK,0);
+
+ clif_movenpc(nd);
+
+ return 0;
+}
+
+int npc_walktoxy(struct npc_data *nd,int x,int y,int easy)
+{
+ struct walkpath_data wpd;
+
+ nullpo_retr(0, nd);
+
+ if(nd->state.state == MS_WALK && path_search(&wpd,nd->bl.m,nd->bl.x,nd->bl.y,x,y,0) )
+ return 1;
+
+ nd->state.walk_easy = easy;
+ nd->to_x=x;
+ nd->to_y=y;
+ if(nd->state.state == MS_WALK) {
+ nd->state.change_walk_target=1;
+ } else {
+ return npc_walktoxy_sub(nd);
+ }
+
+ return 0;
+}
+
+int npc_stop_walking(struct npc_data *nd,int type)
+{
+ nullpo_retr(0, nd);
+
+ if(nd->state.state == MS_WALK || nd->state.state == MS_IDLE) {
+ int dx=0,dy=0;
+
+ nd->walkpath.path_len=0;
+ if(type&4){
+ dx=nd->to_x-nd->bl.x;
+ if(dx<0)
+ dx=-1;
+ else if(dx>0)
+ dx=1;
+ dy=nd->to_y-nd->bl.y;
+ if(dy<0)
+ dy=-1;
+ else if(dy>0)
+ dy=1;
+ }
+ nd->to_x=nd->bl.x+dx;
+ nd->to_y=nd->bl.y+dy;
+ if(dx!=0 || dy!=0){
+ npc_walktoxy_sub(nd);
+ return 0;
+ }
+ npc_changestate(nd,MS_IDLE,0);
+ }
+ if(type&0x01)
+ clif_fixnpcpos(nd);
+ if(type&0x02) {
+ int delay=battle_get_dmotion(&nd->bl);
+ unsigned int tick = gettick();
+ if(nd->canmove_tick < tick)
+ nd->canmove_tick = tick + delay;
+ }
+
+ return 0;
+}
+
+
+//
+// 初期化関係
+//
+
+/*==========================================
+ * 読み込むnpcファイルのクリア
+ *------------------------------------------
+ */
+void npc_clearsrcfile()
+{
+ struct npc_src_list *p=npc_src_first;
+
+ while( p ) {
+ struct npc_src_list *p2=p;
+ p=p->next;
+ free(p2);
+ }
+ npc_src_first=NULL;
+ npc_src_last=NULL;
+}
+/*==========================================
+ * 読み込むnpcファイルの追加
+ *------------------------------------------
+ */
+void npc_addsrcfile(char *name)
+{
+ struct npc_src_list *new;
+ size_t len;
+
+ if ( strcmpi(name,"clear")==0 ) {
+ npc_clearsrcfile();
+ return;
+ }
+
+ len = sizeof(*new) + strlen(name);
+ new=(struct npc_src_list *)aCalloc(1,len);
+ new->next = NULL;
+ strncpy(new->name,name,strlen(name)+1);
+ if (npc_src_first==NULL)
+ npc_src_first = new;
+ if (npc_src_last)
+ npc_src_last->next = new;
+
+ npc_src_last=new;
+}
+/*==========================================
+ * 読み込むnpcファイルの削除
+ *------------------------------------------
+ */
+void npc_delsrcfile(char *name)
+{
+ struct npc_src_list *p=npc_src_first,*pp=NULL,**lp=&npc_src_first;
+
+ if ( strcmpi(name,"all")==0 ) {
+ npc_clearsrcfile();
+ return;
+ }
+
+ for( ; p; lp=&p->next,pp=p,p=p->next ) {
+ if ( strcmp(p->name,name)==0 ) {
+ *lp=p->next;
+ if ( npc_src_last==p )
+ npc_src_last=pp;
+ free(p);
+ break;
+ }
+ }
+}
+
+/*==========================================
+ * warp行解析
+ *------------------------------------------
+ */
+int npc_parse_warp(char *w1,char *w2,char *w3,char *w4)
+{
+ int x,y,xs,ys,to_x,to_y,m;
+ int i,j;
+ char mapname[24],to_mapname[24];
+ struct npc_data *nd;
+
+ // 引数の個数チェック
+ if (sscanf(w1,"%[^,],%d,%d",mapname,&x,&y) != 3 ||
+ sscanf(w4,"%d,%d,%[^,],%d,%d",&xs,&ys,to_mapname,&to_x,&to_y) != 5) {
+ printf("bad warp line : %s\n",w3);
+ return 1;
+ }
+
+ m=map_mapname2mapid(mapname);
+
+ nd=(struct npc_data *)aCalloc(1,sizeof(struct npc_data));
+ nd->bl.id=npc_get_new_npc_id();
+ nd->n=map_addnpc(m,nd);
+
+ nd->bl.prev = nd->bl.next = NULL;
+ nd->bl.m=m;
+ nd->bl.x=x;
+ nd->bl.y=y;
+ nd->dir=0;
+ nd->flag=0;
+ memcpy(nd->name,w3,24);
+ memcpy(nd->exname,w3,24);
+
+ nd->chat_id=0;
+ if (!battle_config.warp_point_debug)
+ nd->class=WARP_CLASS;
+ else
+ nd->class=WARP_DEBUG_CLASS;
+ nd->speed=200;
+ nd->option = 0;
+ nd->opt1 = 0;
+ nd->opt2 = 0;
+ nd->opt3 = 0;
+ memcpy(nd->u.warp.name,to_mapname,16);
+ xs+=2; ys+=2;
+ nd->u.warp.x=to_x;
+ nd->u.warp.y=to_y;
+ nd->u.warp.xs=xs;
+ nd->u.warp.ys=ys;
+
+ for(i=0;i<ys;i++) {
+ for(j=0;j<xs;j++) {
+ int t;
+ t=map_getcell(m,x-xs/2+j,y-ys/2+i);
+ if (t==1 || t==5)
+ continue;
+ map_setcell(m,x-xs/2+j,y-ys/2+i,t|0x80);
+ }
+ }
+
+// printf("warp npc %s %d read done\n",mapname,nd->bl.id);
+ npc_warp++;
+ nd->bl.type=BL_NPC;
+ nd->bl.subtype=WARP;
+ map_addblock(&nd->bl);
+ clif_spawnnpc(nd);
+ strdb_insert(npcname_db,nd->name,nd);
+
+ return 0;
+}
+
+/*==========================================
+ * shop行解析
+ *------------------------------------------
+ */
+static int npc_parse_shop(char *w1,char *w2,char *w3,char *w4)
+{
+ char *p;
+ int x, y, dir, m;
+ int max = 100, pos = 0;
+ char mapname[24];
+ struct npc_data *nd;
+
+ // 引数の個数チェック
+ if (sscanf(w1, "%[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4 ||
+ strchr(w4, ',') == NULL) {
+ printf("bad shop line : %s\n", w3);
+ return 1;
+ }
+ m = map_mapname2mapid(mapname);
+
+ nd = (struct npc_data *)aCalloc(1,sizeof(struct npc_data) +
+ sizeof(nd->u.shop_item[0]) * (max + 1));
+ p = strchr(w4, ',');
+
+ while (p && pos < max) {
+ int nameid,value;
+ p++;
+ if (sscanf(p, "%d:%d", &nameid, &value) != 2)
+ break;
+ nd->u.shop_item[pos].nameid = nameid;
+ if (value < 0) {
+ struct item_data *id = itemdb_search(nameid);
+ value = id->value_buy;
+ }
+ nd->u.shop_item[pos].value = value;
+ pos++;
+ p=strchr(p,',');
+ }
+ if (pos == 0) {
+ free(nd);
+ return 1;
+ }
+ nd->u.shop_item[pos++].nameid = 0;
+
+ nd->bl.prev = nd->bl.next = NULL;
+ nd->bl.m = m;
+ nd->bl.x = x;
+ nd->bl.y = y;
+ nd->bl.id = npc_get_new_npc_id();
+ nd->dir = dir;
+ nd->flag = 0;
+ memcpy(nd->name, w3, 24);
+ nd->class = atoi(w4);
+ nd->speed = 200;
+ nd->chat_id = 0;
+ nd->option = 0;
+ nd->opt1 = 0;
+ nd->opt2 = 0;
+ nd->opt3 = 0;
+
+ nd = (struct npc_data *)aRealloc(nd,
+ sizeof(struct npc_data) + sizeof(nd->u.shop_item[0]) * pos);
+
+ //printf("shop npc %s %d read done\n",mapname,nd->bl.id);
+ npc_shop++;
+ nd->bl.type=BL_NPC;
+ nd->bl.subtype=SHOP;
+ nd->n=map_addnpc(m,nd);
+ map_addblock(&nd->bl);
+ clif_spawnnpc(nd);
+ strdb_insert(npcname_db,nd->name,nd);
+
+ return 0;
+}
+/*==========================================
+ * NPCのラベルデータコンバート
+ *------------------------------------------
+ */
+int npc_convertlabel_db(void *key,void *data,va_list ap)
+{
+ char *lname=(char *)key;
+ int pos=(int)data;
+ struct npc_data *nd;
+ struct npc_label_list *lst;
+ int num;
+ char *p=strchr(lname,':');
+
+ nullpo_retr(0, ap);
+ nullpo_retr(0, nd=va_arg(ap,struct npc_data *));
+
+ lst=nd->u.scr.label_list;
+ num=nd->u.scr.label_list_num;
+ if(!lst){
+ lst=(struct npc_label_list *)aCalloc(1,sizeof(struct npc_label_list));
+ num=0;
+ }else
+ lst=(struct npc_label_list *)aRealloc(lst,sizeof(struct npc_label_list)*(num+1));
+
+ *p='\0';
+ strncpy(lst[num].name,lname,24);
+ *p=':';
+ lst[num].pos=pos;
+ nd->u.scr.label_list=lst;
+ nd->u.scr.label_list_num=num+1;
+ return 0;
+}
+/*==========================================
+ * script行解析
+ *------------------------------------------
+ */
+static int npc_parse_script(char *w1,char *w2,char *w3,char *w4,char *first_line,FILE *fp,int *lines)
+{
+ int x,y,dir=0,m,xs=0,ys=0,class=0; // [Valaris] thanks to fov
+ char mapname[24];
+ unsigned char *srcbuf=NULL,*script;
+ int srcsize=65536;
+ int startline=0;
+ unsigned char line[1024];
+ int i;
+ struct npc_data *nd;
+ int evflag=0;
+ struct dbt *label_db;
+ char *p;
+ struct npc_label_list *label_dup=NULL;
+ int label_dupnum=0;
+ int src_id=0;
+
+ if(strcmp(w1,"-")==0){
+ x=0;y=0;m=-1;
+ }else{
+ // 引数の個数チェック
+ if (sscanf(w1,"%[^,],%d,%d,%d",mapname,&x,&y,&dir) != 4 ||
+ ( strcmp(w2,"script")==0 && strchr(w4,',')==NULL) ) {
+ printf("bad script line : %s\n",w3);
+ return 1;
+ }
+ m = map_mapname2mapid(mapname);
+ }
+
+ if(strcmp(w2,"script")==0){
+ // スクリプトの解析
+ srcbuf=(char *)aCalloc(srcsize,sizeof(char));
+ if (strchr(first_line,'{')) {
+ strcpy(srcbuf,strchr(first_line,'{'));
+ startline=*lines;
+ } else
+ srcbuf[0]=0;
+ while(1) {
+ for(i=strlen(srcbuf)-1;i>=0 && isspace(srcbuf[i]);i--);
+ if (i>=0 && srcbuf[i]=='}')
+ break;
+ fgets(line,1020,fp);
+ (*lines)++;
+ if (feof(fp))
+ break;
+ if (strlen(srcbuf)+strlen(line)+1>=srcsize) {
+ srcsize += 65536;
+ srcbuf = (char *)aRealloc(srcbuf, srcsize);
+ memset(srcbuf + srcsize - 65536, '\0', 65536);
+ }
+ if (srcbuf[0]!='{') {
+ if (strchr(line,'{')) {
+ strcpy(srcbuf,strchr(line,'{'));
+ startline=*lines;
+ }
+ } else
+ strcat(srcbuf,line);
+ }
+ script=parse_script(srcbuf,startline);
+ if (script==NULL) {
+ // script parse error?
+ free(srcbuf);
+ return 1;
+ }
+
+ }else{
+ // duplicateする
+
+ char srcname[128];
+ struct npc_data *nd2;
+ if( sscanf(w2,"duplicate(%[^)])",srcname)!=1 ){
+ printf("bad duplicate name! : %s",w2);
+ return 0;
+ }
+ if( (nd2=npc_name2id(srcname))==NULL ){
+ printf("bad duplicate name! (not exist) : %s\n",srcname);
+ return 0;
+ }
+ script=nd2->u.scr.script;
+ label_dup=nd2->u.scr.label_list;
+ label_dupnum=nd2->u.scr.label_list_num;
+ src_id=nd2->bl.id;
+
+ }// end of スクリプト解析
+
+ nd=(struct npc_data *)aCalloc(1,sizeof(struct npc_data));
+
+ if(m==-1){
+ // スクリプトコピー用のダミーNPC
+
+ }else if( sscanf(w4,"%d,%d,%d",&class,&xs,&ys)==3) {
+ // 接触型NPC
+ int i,j;
+
+ if (xs>=0)xs=xs*2+1;
+ if (ys>=0)ys=ys*2+1;
+
+ if (class>=0) {
+
+ for(i=0;i<ys;i++) {
+ for(j=0;j<xs;j++) {
+ int t;
+ t=map_getcell(m,x-xs/2+j,y-ys/2+i);
+ if (t==1 || t==5)
+ continue;
+ map_setcell(m,x-xs/2+j,y-ys/2+i,t|0x80);
+ }
+ }
+ }
+
+ nd->u.scr.xs=xs;
+ nd->u.scr.ys=ys;
+ } else { // クリック型NPC
+ class=atoi(w4);
+ nd->u.scr.xs=0;
+ nd->u.scr.ys=0;
+ }
+
+ if (class<0 && m>=0) { // イベント型NPC
+ evflag=1;
+ }
+
+ while((p=strchr(w3,':'))) {
+ if (p[1]==':') break;
+ }
+ if (p) {
+ *p=0;
+ memcpy(nd->name,w3,24);
+ memcpy(nd->exname,p+2,24);
+ }else{
+ memcpy(nd->name,w3,24);
+ memcpy(nd->exname,w3,24);
+ }
+
+ nd->bl.prev = nd->bl.next = NULL;
+ nd->bl.m = m;
+ nd->bl.x = x;
+ nd->bl.y = y;
+ nd->bl.id=npc_get_new_npc_id();
+ nd->dir = dir;
+ nd->flag=0;
+ nd->class=class;
+ nd->speed=200;
+ nd->u.scr.script=script;
+ nd->u.scr.src_id=src_id;
+ nd->chat_id=0;
+ nd->option = 0;
+ nd->opt1 = 0;
+ nd->opt2 = 0;
+ nd->opt3 = 0;
+ nd->walktimer=-1;
+
+ //printf("script npc %s %d %d read done\n",mapname,nd->bl.id,nd->class);
+ npc_script++;
+ nd->bl.type=BL_NPC;
+ nd->bl.subtype=SCRIPT;
+ if(m>=0){
+ nd->n=map_addnpc(m,nd);
+ map_addblock(&nd->bl);
+
+ if (evflag) { // イベント型
+ struct event_data *ev=(struct event_data *)aCalloc(1,sizeof(struct event_data));
+ ev->nd=nd;
+ ev->pos=0;
+ strdb_insert(ev_db,nd->exname,ev);
+ }else
+ clif_spawnnpc(nd);
+ }
+ strdb_insert(npcname_db,nd->exname,nd);
+
+
+ //-----------------------------------------
+ // ラベルデータの準備
+ if(srcbuf){
+ // script本体がある場合の処理
+
+ // ラベルデータのコンバート
+ label_db=script_get_label_db();
+ strdb_foreach(label_db,npc_convertlabel_db,nd);
+
+ // もう使わないのでバッファ解放
+ free(srcbuf);
+
+ }else{
+ // duplicate
+
+// nd->u.scr.label_list=malloc(sizeof(struct npc_label_list)*label_dupnum);
+// memcpy(nd->u.scr.label_list,label_dup,sizeof(struct npc_label_list)*label_dupnum);
+
+ nd->u.scr.label_list=label_dup; // ラベルデータ共有
+ nd->u.scr.label_list_num=label_dupnum;
+ }
+
+ //-----------------------------------------
+ // イベント用ラベルデータのエクスポート
+ for(i=0;i<nd->u.scr.label_list_num;i++){
+ char *lname=nd->u.scr.label_list[i].name;
+ int pos=nd->u.scr.label_list[i].pos;
+
+ if ((lname[0]=='O' || lname[0]=='o')&&(lname[1]=='N' || lname[1]=='n')) {
+ struct event_data *ev;
+ char *buf;
+ // エクスポートされる
+ ev=(struct event_data *)aCalloc(1,sizeof(struct event_data));
+ buf=(char *)aCalloc(50,sizeof(char));
+ if (strlen(lname)>24) {
+ printf("npc_parse_script: label name error !\n");
+ exit(1);
+ }else{
+ ev->nd=nd;
+ ev->pos=pos;
+ sprintf(buf,"%s::%s",nd->exname,lname);
+ strdb_insert(ev_db,buf,ev);
+ }
+ }
+ }
+
+ //-----------------------------------------
+ // ラベルデータからタイマーイベント取り込み
+ for(i=0;i<nd->u.scr.label_list_num;i++){
+ int t=0,k=0;
+ char *lname=nd->u.scr.label_list[i].name;
+ int pos=nd->u.scr.label_list[i].pos;
+ if(sscanf(lname,"OnTimer%d%n",&t,&k)==1 && lname[k]=='\0') {
+ // タイマーイベント
+ struct npc_timerevent_list *te=nd->u.scr.timer_event;
+ int j,k=nd->u.scr.timeramount;
+ if(te==NULL)
+ te=(struct npc_timerevent_list *)aCalloc(1,sizeof(struct npc_timerevent_list));
+ else
+ te=(struct npc_timerevent_list *)aRealloc( te, sizeof(struct npc_timerevent_list) * (k+1) );
+ for(j=0;j<k;j++){
+ if(te[j].timer>t){
+ memmove(te+j+1,te+j,sizeof(struct npc_timerevent_list)*(k-j));
+ break;
+ }
+ }
+ te[j].timer=t;
+ te[j].pos=pos;
+ nd->u.scr.timer_event=te;
+ nd->u.scr.timeramount=k+1;
+ }
+ }
+ nd->u.scr.nexttimer=-1;
+ nd->u.scr.timerid=-1;
+
+
+ return 0;
+}
+
+/*==========================================
+ * function行解析
+ *------------------------------------------
+ */
+static int npc_parse_function(char *w1,char *w2,char *w3,char *w4,char *first_line,FILE *fp,int *lines)
+{
+ char *srcbuf=NULL,*script;
+ int srcsize=65536;
+ int startline=0;
+ char line[1024];
+ int i;
+// struct dbt *label_db;
+ char *p;
+
+ // スクリプトの解析
+ srcbuf=(char *)aCalloc(srcsize,sizeof(char));
+ if (strchr(first_line,'{')) {
+ strcpy(srcbuf,strchr(first_line,'{'));
+ startline=*lines;
+ } else
+ srcbuf[0]=0;
+ while(1) {
+ for(i=strlen(srcbuf)-1;i>=0 && isspace(srcbuf[i]);i--);
+ if (i>=0 && srcbuf[i]=='}')
+ break;
+ fgets(line,1020,fp);
+ (*lines)++;
+ if (feof(fp))
+ break;
+ if (strlen(srcbuf)+strlen(line)+1>=srcsize) {
+ srcsize += 65536;
+ srcbuf = (char *)aRealloc(srcbuf, srcsize);
+ memset(srcbuf + srcsize - 65536, '\0', 65536);
+ }
+ if (srcbuf[0]!='{') {
+ if (strchr(line,'{')) {
+ strcpy(srcbuf,strchr(line,'{'));
+ startline=*lines;
+ }
+ } else
+ strcat(srcbuf,line);
+ }
+ script=parse_script(srcbuf,startline);
+ if (script==NULL) {
+ // script parse error?
+ free(srcbuf);
+ return 1;
+ }
+
+ p=(char *)aCalloc(50,sizeof(char));
+
+ strncpy(p,w3,50);
+ strdb_insert(script_get_userfunc_db(),p,script);
+
+// label_db=script_get_label_db();
+
+ // もう使わないのでバッファ解放
+ free(srcbuf);
+
+// printf("function %s => %p\n",p,script);
+
+ return 0;
+}
+
+
+/*==========================================
+ * mob行解析
+ *------------------------------------------
+ */
+int npc_parse_mob(char *w1,char *w2,char *w3,char *w4)
+{
+ int m,x,y,xs,ys,class,num,delay1,delay2;
+ int i;
+ char mapname[24];
+ char eventname[24]="";
+ struct mob_data *md;
+
+ xs=ys=0;
+ delay1=delay2=0;
+ // 引数の個数チェック
+ if (sscanf(w1,"%[^,],%d,%d,%d,%d",mapname,&x,&y,&xs,&ys) < 3 ||
+ sscanf(w4,"%d,%d,%d,%d,%s",&class,&num,&delay1,&delay2,eventname) < 2 ) {
+ printf("bad monster line : %s\n",w3);
+ return 1;
+ }
+
+ m=map_mapname2mapid(mapname);
+
+ if ( num>1 && battle_config.mob_count_rate!=100) {
+ if ( (num=num*battle_config.mob_count_rate/100)<1 )
+ num=1;
+ }
+
+ for(i=0;i<num;i++) {
+ md=(struct mob_data *)aCalloc(1,sizeof(struct mob_data));
+
+ md->bl.prev=NULL;
+ md->bl.next=NULL;
+ md->bl.m=m;
+ md->bl.x=x;
+ md->bl.y=y;
+ if(strcmp(w3,"--en--")==0)
+ memcpy(md->name,mob_db[class].name,24);
+ else if(strcmp(w3,"--ja--")==0)
+ memcpy(md->name,mob_db[class].jname,24);
+ else
+ memcpy(md->name,w3,24);
+
+ md->n = i;
+ md->base_class = md->class = class;
+ md->bl.id=npc_get_new_npc_id();
+ md->m =m;
+ md->x0=x;
+ md->y0=y;
+ md->xs=xs;
+ md->ys=ys;
+ md->spawndelay1=delay1;
+ md->spawndelay2=delay2;
+
+ memset(&md->state,0,sizeof(md->state));
+ md->timer = -1;
+ md->target_id=0;
+ md->attacked_id=0;
+ md->speed=mob_db[class].speed;
+
+ if (mob_db[class].mode&0x02)
+ md->lootitem=(struct item *)aCalloc(LOOTITEM_SIZE,sizeof(struct item));
+ else
+ md->lootitem=NULL;
+
+ if (strlen(eventname)>=4) {
+ memcpy(md->npc_event,eventname,24);
+ }else
+ memset(md->npc_event,0,24);
+
+ md->bl.type=BL_MOB;
+ map_addiddb(&md->bl);
+ mob_spawn(md->bl.id);
+
+ npc_mob++;
+ }
+ //printf("warp npc %s %d read done\n",mapname,nd->bl.id);
+
+ return 0;
+}
+
+/*==========================================
+ * マップフラグ行の解析
+ *------------------------------------------
+ */
+static int npc_parse_mapflag(char *w1,char *w2,char *w3,char *w4)
+{
+ int m;
+ char mapname[24],savemap[16];
+ int savex,savey;
+ char drop_arg1[16],drop_arg2[16];
+ int drop_id=0,drop_type=0,drop_per=0;
+
+ // 引数の個数チェック
+// if ( sscanf(w1,"%[^,],%d,%d,%d",mapname,&x,&y,&dir) != 4 )
+ if ( sscanf(w1,"%[^,]",mapname) != 1 )
+ return 1;
+
+ m=map_mapname2mapid(mapname);
+ if (m<0)
+ return 1;
+
+//マップフラグ
+ if ( strcmpi(w3,"nosave")==0) {
+ if (strcmp(w4,"SavePoint")==0) {
+ memcpy(map[m].save.map,"SavePoint",16);
+ map[m].save.x=-1;
+ map[m].save.y=-1;
+ }else if (sscanf(w4,"%[^,],%d,%d",savemap,&savex,&savey)==3) {
+ memcpy(map[m].save.map,savemap,16);
+ map[m].save.x=savex;
+ map[m].save.y=savey;
+ }
+ map[m].flag.nosave=1;
+ }
+ else if (strcmpi(w3,"nomemo")==0) {
+ map[m].flag.nomemo=1;
+ }
+ else if (strcmpi(w3,"noteleport")==0) {
+ map[m].flag.noteleport=1;
+ }
+ else if (strcmpi(w3,"nowarp")==0) {
+ map[m].flag.nowarp=1;
+ }
+ else if (strcmpi(w3,"nowarpto")==0) {
+ map[m].flag.nowarpto=1;
+ }
+ else if (strcmpi(w3,"noreturn")==0) {
+ map[m].flag.noreturn=1;
+ }
+ else if (strcmpi(w3,"monster_noteleport")==0) {
+ map[m].flag.monster_noteleport=1;
+ }
+ else if (strcmpi(w3,"nobranch")==0) {
+ map[m].flag.nobranch=1;
+ }
+ else if (strcmpi(w3,"nopenalty")==0) {
+ map[m].flag.nopenalty=1;
+ }
+ else if (strcmpi(w3,"pvp")==0) {
+ map[m].flag.pvp=1;
+ }
+ else if (strcmpi(w3,"pvp_noparty")==0) {
+ map[m].flag.pvp_noparty=1;
+ }
+ else if (strcmpi(w3,"pvp_noguild")==0) {
+ map[m].flag.pvp_noguild=1;
+ }
+ else if (strcmpi(w3,"pvp_nightmaredrop")==0) {
+ if (sscanf(w4,"%[^,],%[^,],%d",drop_arg1,drop_arg2,&drop_per)==3) { int i;
+ if(strcmp(drop_arg1,"random")==0)
+ drop_id = -1;
+ else if(itemdb_exists( (drop_id=atoi(drop_arg1)) )==NULL)
+ drop_id = 0;
+ if(strcmp(drop_arg2,"inventory")==0)
+ drop_type = 1;
+ else if(strcmp(drop_arg2,"equip")==0)
+ drop_type = 2;
+ else if(strcmp(drop_arg2,"all")==0)
+ drop_type = 3;
+
+ if(drop_id != 0){
+ for (i=0;i<MAX_DROP_PER_MAP;i++){
+ if(map[m].drop_list[i].drop_id==0){
+ map[m].drop_list[i].drop_id = drop_id;
+ map[m].drop_list[i].drop_type = drop_type;
+ map[m].drop_list[i].drop_per = drop_per;
+ break;
+ }
+ }
+ map[m].flag.pvp_nightmaredrop=1;
+ }
+ }
+ }
+ else if (strcmpi(w3,"pvp_nocalcrank")==0) {
+ map[m].flag.pvp_nocalcrank=1;
+ }
+ else if (strcmpi(w3,"gvg")==0) {
+ map[m].flag.gvg=1;
+ }
+ else if (strcmpi(w3,"gvg_noparty")==0) {
+ map[m].flag.gvg_noparty=1;
+ }
+ else if (strcmpi(w3,"nozenypenalty")==0) {
+ map[m].flag.nozenypenalty=1;
+ }
+ else if (strcmpi(w3,"notrade")==0) {
+ map[m].flag.notrade=1;
+ }
+ else if (strcmpi(w3,"noskill")==0) {
+ map[m].flag.noskill=1;
+ }
+ else if (battle_config.pk_mode && strcmpi(w3,"nopvp")==0) { // nopvp for pk mode [Valaris]
+ map[m].flag.nopvp=1;
+ map[m].flag.pvp=0;
+ }
+ else if (strcmpi(w3,"noicewall")==0) { // noicewall [Valaris]
+ map[m].flag.noicewall=1;
+ }
+ else if (strcmpi(w3,"snow")==0) { // snow [Valaris]
+ map[m].flag.snow=1;
+ }
+ else if (strcmpi(w3,"fog")==0) { // fog [Valaris]
+ map[m].flag.fog=1;
+ }
+ else if (strcmpi(w3,"sakura")==0) { // sakura [Valaris]
+ map[m].flag.sakura=1;
+ }
+ else if (strcmpi(w3,"leaves")==0) { // leaves [Valaris]
+ map[m].flag.leaves=1;
+ }
+ else if (strcmpi(w3,"rain")==0) { // rain [Valaris]
+ map[m].flag.rain=1;
+ }
+
+ return 0;
+}
+
+static int ev_db_final(void *key,void *data,va_list ap)
+{
+ free(data);
+ if(strstr(key,"::")!=NULL)
+ free(key);
+ return 0;
+}
+static int npcname_db_final(void *key,void *data,va_list ap)
+{
+ return 0;
+}
+/*==========================================
+ * 終了
+ *------------------------------------------
+ */
+int do_final_npc(void)
+{
+ int i;
+ struct block_list *bl;
+ struct npc_data *nd;
+ struct mob_data *md;
+ struct chat_data *cd;
+ struct pet_data *pd;
+
+ if(ev_db)
+ strdb_final(ev_db,ev_db_final);
+ if(npcname_db)
+ strdb_final(npcname_db,npcname_db_final);
+
+ for(i=START_NPC_NUM;i<npc_id;i++){
+ if((bl=map_id2bl(i))){
+ if(bl->type == BL_NPC && (nd = (struct npc_data *)bl)){
+ if(nd->chat_id && (cd=(struct chat_data*)map_id2bl(nd->chat_id))){
+ free(cd);
+ cd = NULL;
+ }
+ if(nd->bl.subtype == SCRIPT){
+ if(nd->u.scr.timer_event)
+ free(nd->u.scr.timer_event);
+ if(nd->u.scr.src_id==0){
+ if(nd->u.scr.script){
+ free(nd->u.scr.script);
+ nd->u.scr.script=NULL;
+ }
+ if(nd->u.scr.label_list){
+ free(nd->u.scr.label_list);
+ nd->u.scr.label_list = NULL;
+ }
+ }
+ }
+ free(nd);
+ nd = NULL;
+ }else if(bl->type == BL_MOB && (md = (struct mob_data *)bl)){
+ if(md->lootitem){
+ free(md->lootitem);
+ md->lootitem = NULL;
+ }
+ free(md);
+ md = NULL;
+ }else if(bl->type == BL_PET && (pd = (struct pet_data *)bl)){
+ free(pd);
+ pd = NULL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+void ev_release(struct dbn *db, int which)
+{
+ if (which & 0x1)
+ free(db->key);
+ if (which & 0x2)
+ free(db->data);
+}
+
+/*==========================================
+ * npc初期化
+ *------------------------------------------
+ */
+int do_init_npc(void)
+{
+ struct npc_src_list *nsl;
+ FILE *fp;
+ char line[1024];
+ int m,lines;
+
+ ev_db=strdb_init(24);
+ npcname_db=strdb_init(24);
+
+ ev_db->release = ev_release;
+
+ memset(&ev_tm_b,-1,sizeof(ev_tm_b));
+
+ for(nsl=npc_src_first;nsl;nsl=nsl->next) {
+ if(nsl->prev){
+ free(nsl->prev);
+ nsl->prev = NULL;
+ }
+ fp=fopen(nsl->name,"r");
+ if (fp==NULL) {
+ printf("file not found : %s\n",nsl->name);
+ exit(1);
+ }
+ lines=0;
+ while(fgets(line,1020,fp)) {
+ char w1[1024],w2[1024],w3[1024],w4[1024],mapname[1024];
+ int i,j,w4pos,count;
+ lines++;
+
+ if (line[0] == '/' && line[1] == '/')
+ continue;
+ // 不要なスペースやタブの連続は詰める
+ for(i=j=0;line[i];i++) {
+ if (line[i]==' ') {
+ if (!((line[i+1] && (isspace(line[i+1]) || line[i+1]==',')) ||
+ (j && line[j-1]==',')))
+ line[j++]=' ';
+ } else if (line[i]=='\t') {
+ if (!(j && line[j-1]=='\t'))
+ line[j++]='\t';
+ } else
+ line[j++]=line[i];
+ }
+ // 最初はタブ区切りでチェックしてみて、ダメならスペース区切りで確認
+ if ((count=sscanf(line,"%[^\t]\t%[^\t]\t%[^\t\r\n]\t%n%[^\t\r\n]",w1,w2,w3,&w4pos,w4)) < 3 &&
+ (count=sscanf(line,"%s%s%s%n%s",w1,w2,w3,&w4pos,w4)) < 3) {
+ continue;
+ }
+ // マップの存在確認
+ if( strcmp(w1,"-")!=0 && strcmpi(w1,"function")!=0 ){
+ sscanf(w1,"%[^,]",mapname);
+ m = map_mapname2mapid(mapname);
+ if (strlen(mapname)>16 || m<0) {
+ // "mapname" is not assigned to this server
+ continue;
+ }
+ }
+ if (strcmpi(w2,"warp")==0 && count > 3) {
+ npc_parse_warp(w1,w2,w3,w4);
+ } else if (strcmpi(w2,"shop")==0 && count > 3) {
+ npc_parse_shop(w1,w2,w3,w4);
+ } else if (strcmpi(w2,"script")==0 && count > 3) {
+ if( strcmpi(w1,"function")==0 ){
+ npc_parse_function(w1,w2,w3,w4,line+w4pos,fp,&lines);
+ }else{
+ npc_parse_script(w1,w2,w3,w4,line+w4pos,fp,&lines);
+ }
+ } else if ( (i=0,sscanf(w2,"duplicate%n",&i), (i>0 && w2[i]=='(')) && count > 3) {
+ npc_parse_script(w1,w2,w3,w4,line+w4pos,fp,&lines);
+ } else if (strcmpi(w2,"monster")==0 && count > 3) {
+ npc_parse_mob(w1,w2,w3,w4);
+ } else if (strcmpi(w2,"mapflag")==0 && count >= 3) {
+ npc_parse_mapflag(w1,w2,w3,w4);
+ }
+ }
+ fclose(fp);
+ printf("\rLoading NPCs [%d]: %-54s",npc_id-START_NPC_NUM,nsl->name);
+ fflush(stdout);
+ }
+ printf("\rNPCs Loaded: %d [Warps:%d Shops:%d Scripts:%d Mobs:%d]\n",
+ npc_id-START_NPC_NUM,npc_warp,npc_shop,npc_script,npc_mob);
+
+ add_timer_func_list(npc_walktimer,"npc_walktimer"); // [Valaris]
+ add_timer_func_list(npc_event_timer,"npc_event_timer");
+ add_timer_func_list(npc_event_do_clock,"npc_event_do_clock");
+ add_timer_func_list(npc_timerevent,"npc_timerevent");
+
+ //exit(1);
+
+ return 0;
+}
diff --git a/src/map/npc.h b/src/map/npc.h
new file mode 100644
index 000000000..9bc7a6c96
--- /dev/null
+++ b/src/map/npc.h
@@ -0,0 +1,52 @@
+// $Id: npc.h,v 1.5 2004/09/25 11:39:17 MouseJstr Exp $
+#ifndef _NPC_H_
+#define _NPC_H_
+
+#define START_NPC_NUM 110000000
+
+#define WARP_CLASS 45
+#define WARP_DEBUG_CLASS 722
+#define INVISIBLE_CLASS 32767
+
+int npc_event_dequeue(struct map_session_data *sd);
+int npc_event_timer(int tid,unsigned int tick,int id,int data);
+int npc_event(struct map_session_data *sd,const char *npcname,int);
+int npc_timer_event(const char *eventname); // Added by RoVeRT
+int npc_command(struct map_session_data *sd,char *npcname,char *command);
+int npc_touch_areanpc(struct map_session_data *,int,int,int);
+int npc_click(struct map_session_data *,int);
+int npc_scriptcont(struct map_session_data *,int);
+int npc_checknear(struct map_session_data *,int);
+int npc_buysellsel(struct map_session_data *,int,int);
+int npc_buylist(struct map_session_data *,int,unsigned short *);
+int npc_selllist(struct map_session_data *,int,unsigned short *);
+int npc_parse_mob(char *w1,char *w2,char *w3,char *w4);
+int npc_parse_warp(char *w1,char *w2,char *w3,char *w4);
+
+int npc_enable(const char *name,int flag);
+struct npc_data* npc_name2id(const char *name);
+
+int npc_walktoxy(struct npc_data *nd,int x,int y,int easy); // npc walking [Valaris]
+int npc_stop_walking(struct npc_data *nd,int type);
+int npc_changestate(struct npc_data *nd,int state,int type);
+
+int npc_get_new_npc_id(void);
+
+void npc_addsrcfile(char *);
+void npc_delsrcfile(char *);
+int do_final_npc(void);
+int do_init_npc(void);
+int npc_event_do_oninit(void);
+int npc_do_ontimer(int,struct map_session_data *,int);
+
+int npc_event_doall(const char *name);
+int npc_event_do(const char *name);
+
+int npc_timerevent_start(struct npc_data *nd);
+int npc_timerevent_stop(struct npc_data *nd);
+int npc_gettimerevent_tick(struct npc_data *nd);
+int npc_settimerevent_tick(struct npc_data *nd,int newtimer);
+int npc_delete(struct npc_data *nd);
+
+#endif
+
diff --git a/src/map/party.c b/src/map/party.c
new file mode 100644
index 000000000..d433fa3b8
--- /dev/null
+++ b/src/map/party.c
@@ -0,0 +1,644 @@
+// $Id: party.c,v 1.2 2004/09/22 02:59:47 Akitasha Exp $
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "party.h"
+#include "db.h"
+#include "timer.h"
+#include "socket.h"
+#include "nullpo.h"
+#include "malloc.h"
+#include "pc.h"
+#include "map.h"
+#include "battle.h"
+#include "intif.h"
+#include "clif.h"
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+#define PARTY_SEND_XYHP_INVERVAL 1000 // 座標やHP送信の間隔
+
+static struct dbt* party_db;
+
+int party_send_xyhp_timer(int tid,unsigned int tick,int id,int data);
+/*==========================================
+ * 終了
+ *------------------------------------------
+ */
+static int party_db_final(void *key,void *data,va_list ap)
+{
+ free(data);
+ return 0;
+}
+void do_final_party(void)
+{
+ if(party_db)
+ numdb_final(party_db,party_db_final);
+}
+// 初期化
+void do_init_party(void)
+{
+ party_db=numdb_init();
+ add_timer_func_list(party_send_xyhp_timer,"party_send_xyhp_timer");
+ add_timer_interval(gettick()+PARTY_SEND_XYHP_INVERVAL,party_send_xyhp_timer,0,0,PARTY_SEND_XYHP_INVERVAL);
+}
+
+// 検索
+struct party *party_search(int party_id)
+{
+ return numdb_search(party_db,party_id);
+}
+int party_searchname_sub(void *key,void *data,va_list ap)
+{
+ struct party *p=(struct party *)data,**dst;
+ char *str;
+ str=va_arg(ap,char *);
+ dst=va_arg(ap,struct party **);
+ if(strcmpi(p->name,str)==0)
+ *dst=p;
+ return 0;
+}
+// パーティ名検索
+struct party* party_searchname(char *str)
+{
+ struct party *p=NULL;
+ numdb_foreach(party_db,party_searchname_sub,str,&p);
+ return p;
+}
+// 作成要求
+int party_create(struct map_session_data *sd,char *name)
+{
+ nullpo_retr(0, sd);
+
+ if(sd->status.party_id==0)
+ intif_create_party(sd,name);
+ else
+ clif_party_created(sd,2);
+ return 0;
+}
+
+// 作成可否
+int party_created(int account_id,int fail,int party_id,char *name)
+{
+ struct map_session_data *sd;
+ sd=map_id2sd(account_id);
+
+ nullpo_retr(0, sd);
+
+ if(fail==0){
+ struct party *p;
+ sd->status.party_id=party_id;
+ if((p=numdb_search(party_db,party_id))!=NULL){
+ printf("party: id already exists!\n");
+ exit(1);
+ }
+ p=(struct party *)aCalloc(1,sizeof(struct party));
+ p->party_id=party_id;
+ memcpy(p->name,name,24);
+ numdb_insert(party_db,party_id,p);
+ clif_party_created(sd,0);
+ }else{
+ clif_party_created(sd,1);
+ }
+ return 0;
+}
+
+// 情報要求
+int party_request_info(int party_id)
+{
+ return intif_request_partyinfo(party_id);
+}
+
+// 所属キャラの確認
+int party_check_member(struct party *p)
+{
+ int i;
+ struct map_session_data *sd;
+
+ nullpo_retr(0, p);
+
+ for(i=0;i<fd_max;i++){
+ if(session[i] && (sd=session[i]->session_data) && sd->state.auth){
+ if(sd->status.party_id==p->party_id){
+ int j,f=1;
+ for(j=0;j<MAX_PARTY;j++){ // パーティにデータがあるか確認
+ if( p->member[j].account_id==sd->status.account_id){
+ if( strcmp(p->member[j].name,sd->status.name)==0 )
+ f=0; // データがある
+ else
+ p->member[j].sd=NULL; // 同垢別キャラだった
+ }
+ }
+ if(f){
+ sd->status.party_id=0;
+ if(battle_config.error_log)
+ printf("party: check_member %d[%s] is not member\n",sd->status.account_id,sd->status.name);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+// 情報所得失敗(そのIDのキャラを全部未所属にする)
+int party_recv_noinfo(int party_id)
+{
+ int i;
+ struct map_session_data *sd;
+ for(i=0;i<fd_max;i++){
+ if(session[i] && (sd=session[i]->session_data) && sd->state.auth){
+ if(sd->status.party_id==party_id)
+ sd->status.party_id=0;
+ }
+ }
+ return 0;
+}
+// 情報所得
+int party_recv_info(struct party *sp)
+{
+ struct party *p;
+ int i;
+
+ nullpo_retr(0, sp);
+
+ if((p=numdb_search(party_db,sp->party_id))==NULL){
+ p=(struct party *)aCalloc(1,sizeof(struct party));
+ numdb_insert(party_db,sp->party_id,p);
+
+ // 最初のロードなのでユーザーのチェックを行う
+ party_check_member(sp);
+ }
+ memcpy(p,sp,sizeof(struct party));
+
+ for(i=0;i<MAX_PARTY;i++){ // sdの設定
+ struct map_session_data *sd = map_id2sd(p->member[i].account_id);
+ p->member[i].sd=(sd!=NULL && sd->status.party_id==p->party_id)?sd:NULL;
+ }
+
+ clif_party_info(p,-1);
+
+ for(i=0;i<MAX_PARTY;i++){ // 設定情報の送信
+// struct map_session_data *sd = map_id2sd(p->member[i].account_id);
+ struct map_session_data *sd = p->member[i].sd;
+ if(sd!=NULL && sd->party_sended==0){
+ clif_party_option(p,sd,0x100);
+ sd->party_sended=1;
+ }
+ }
+
+ return 0;
+}
+
+// パーティへの勧誘
+int party_invite(struct map_session_data *sd,int account_id)
+{
+ struct map_session_data *tsd= map_id2sd(account_id);
+ struct party *p=party_search(sd->status.party_id);
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if(tsd==NULL || p==NULL)
+ return 0;
+ if(!battle_config.invite_request_check) {
+ if (tsd->guild_invite>0 || tsd->trade_partner) { // 相手が取引中かどうか
+ clif_party_inviteack(sd,tsd->status.name,0);
+ return 0;
+ }
+ }
+ if( tsd->status.party_id>0 || tsd->party_invite>0 ){ // 相手の所属確認
+ clif_party_inviteack(sd,tsd->status.name,0);
+ return 0;
+ }
+ for(i=0;i<MAX_PARTY;i++){ // 同アカウント確認
+ if(p->member[i].account_id==account_id){
+ clif_party_inviteack(sd,tsd->status.name,0);
+ return 0;
+ }
+ }
+
+ tsd->party_invite=sd->status.party_id;
+ tsd->party_invite_account=sd->status.account_id;
+
+ clif_party_invite(sd,tsd);
+ return 0;
+}
+// パーティ勧誘への返答
+int party_reply_invite(struct map_session_data *sd,int account_id,int flag)
+{
+ struct map_session_data *tsd= map_id2sd(account_id);
+
+ nullpo_retr(0, sd);
+
+ if(flag==1){ // 承諾
+ //inter鯖へ追加要求
+ intif_party_addmember( sd->party_invite, sd->status.account_id );
+ return 0;
+ }
+ else { // 拒否
+ sd->party_invite=0;
+ sd->party_invite_account=0;
+ if(tsd==NULL)
+ return 0;
+ clif_party_inviteack(tsd,sd->status.name,1);
+ }
+ return 0;
+}
+// パーティが追加された
+int party_member_added(int party_id,int account_id,int flag)
+{
+ struct map_session_data *sd= map_id2sd(account_id),*sd2;
+ if(sd==NULL && flag==0){
+ if(battle_config.error_log)
+ printf("party: member added error %d is not online\n",account_id);
+ intif_party_leave(party_id,account_id); // キャラ側に登録できなかったため脱退要求を出す
+ return 0;
+ }
+ sd2=map_id2sd(sd->party_invite_account);
+ sd->party_invite=0;
+ sd->party_invite_account=0;
+
+ if(flag==1){ // 失敗
+ if( sd2!=NULL )
+ clif_party_inviteack(sd2,sd->status.name,0);
+ return 0;
+ }
+
+ // 成功
+ sd->party_sended=0;
+ sd->status.party_id=party_id;
+
+ if( sd2!=NULL)
+ clif_party_inviteack(sd2,sd->status.name,2);
+
+ // いちおう競合確認
+ party_check_conflict(sd);
+
+ return 0;
+}
+// パーティ除名要求
+int party_removemember(struct map_session_data *sd,int account_id,char *name)
+{
+ struct party *p;
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if( (p = party_search(sd->status.party_id)) == NULL )
+ return 0;
+
+ for(i=0;i<MAX_PARTY;i++){ // リーダーかどうかチェック
+ if(p->member[i].account_id==sd->status.account_id)
+ if(p->member[i].leader==0)
+ return 0;
+ }
+
+ for(i=0;i<MAX_PARTY;i++){ // 所属しているか調べる
+ if(p->member[i].account_id==account_id){
+ intif_party_leave(p->party_id,account_id);
+ return 0;
+ }
+ }
+ return 0;
+}
+
+// パーティ脱退要求
+int party_leave(struct map_session_data *sd)
+{
+ struct party *p;
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if( (p = party_search(sd->status.party_id)) == NULL )
+ return 0;
+
+ for(i=0;i<MAX_PARTY;i++){ // 所属しているか
+ if(p->member[i].account_id==sd->status.account_id){
+ intif_party_leave(p->party_id,sd->status.account_id);
+ return 0;
+ }
+ }
+ return 0;
+}
+// パーティメンバが脱退した
+int party_member_leaved(int party_id,int account_id,char *name)
+{
+ struct map_session_data *sd=map_id2sd(account_id);
+ struct party *p=party_search(party_id);
+ if(p!=NULL){
+ int i;
+ for(i=0;i<MAX_PARTY;i++)
+ if(p->member[i].account_id==account_id){
+ clif_party_leaved(p,sd,account_id,name,0x00);
+ p->member[i].account_id=0;
+ p->member[i].sd=NULL;
+ }
+ }
+ if(sd!=NULL && sd->status.party_id==party_id){
+ sd->status.party_id=0;
+ sd->party_sended=0;
+ }
+ return 0;
+}
+// パーティ解散通知
+int party_broken(int party_id)
+{
+ struct party *p;
+ int i;
+ if( (p=party_search(party_id))==NULL )
+ return 0;
+
+ for(i=0;i<MAX_PARTY;i++){
+ if(p->member[i].sd!=NULL){
+ clif_party_leaved(p,p->member[i].sd,
+ p->member[i].account_id,p->member[i].name,0x10);
+ p->member[i].sd->status.party_id=0;
+ p->member[i].sd->party_sended=0;
+ }
+ }
+ numdb_erase(party_db,party_id);
+ return 0;
+}
+// パーティの設定変更要求
+int party_changeoption(struct map_session_data *sd,int exp,int item)
+{
+ struct party *p;
+
+ nullpo_retr(0, sd);
+
+ if( sd->status.party_id==0 || (p=party_search(sd->status.party_id))==NULL )
+ return 0;
+ intif_party_changeoption(sd->status.party_id,sd->status.account_id,exp,item);
+ return 0;
+}
+// パーティの設定変更通知
+int party_optionchanged(int party_id,int account_id,int exp,int item,int flag)
+{
+ struct party *p;
+ struct map_session_data *sd=map_id2sd(account_id);
+ if( (p=party_search(party_id))==NULL)
+ return 0;
+
+ if(!(flag&0x01)) p->exp=exp;
+ if(!(flag&0x10)) p->item=item;
+ clif_party_option(p,sd,flag);
+ return 0;
+}
+
+// パーティメンバの移動通知
+int party_recv_movemap(int party_id,int account_id,char *map,int online,int lv)
+{
+ struct party *p;
+ int i;
+ if( (p=party_search(party_id))==NULL)
+ return 0;
+ for(i=0;i<MAX_PARTY;i++){
+ struct party_member *m=&p->member[i];
+ if( m == NULL ){
+ printf("party_recv_movemap nullpo?\n");
+ return 0;
+ }
+ if(m->account_id==account_id){
+ memcpy(m->map,map,16);
+ m->online=online;
+ m->lv=lv;
+ break;
+ }
+ }
+ if(i==MAX_PARTY){
+ if(battle_config.error_log)
+ printf("party: not found member %d on %d[%s]",account_id,party_id,p->name);
+ return 0;
+ }
+
+ for(i=0;i<MAX_PARTY;i++){ // sd再設定
+ struct map_session_data *sd= map_id2sd(p->member[i].account_id);
+ p->member[i].sd=(sd!=NULL && sd->status.party_id==p->party_id)?sd:NULL;
+ }
+
+ party_send_xy_clear(p); // 座標再通知要請
+
+ clif_party_info(p,-1);
+ return 0;
+}
+
+// パーティメンバの移動
+int party_send_movemap(struct map_session_data *sd)
+{
+ struct party *p;
+
+ nullpo_retr(0, sd);
+
+ if( sd->status.party_id==0 )
+ return 0;
+ intif_party_changemap(sd,1);
+
+ if( sd->party_sended!=0 ) // もうパーティデータは送信済み
+ return 0;
+
+ // 競合確認
+ party_check_conflict(sd);
+
+ // あるならパーティ情報送信
+ if( (p=party_search(sd->status.party_id))!=NULL ){
+ party_check_member(p); // 所属を確認する
+ if(sd->status.party_id==p->party_id){
+ clif_party_info(p,sd->fd);
+ clif_party_option(p,sd,0x100);
+ sd->party_sended=1;
+ }
+ }
+
+ return 0;
+}
+// パーティメンバのログアウト
+int party_send_logout(struct map_session_data *sd)
+{
+ struct party *p;
+
+ nullpo_retr(0, sd);
+
+ if( sd->status.party_id>0 )
+ intif_party_changemap(sd,0);
+
+ // sdが無効になるのでパーティ情報から削除
+ if( (p=party_search(sd->status.party_id))!=NULL ){
+ int i;
+ for(i=0;i<MAX_PARTY;i++)
+ if(p->member[i].sd==sd)
+ p->member[i].sd=NULL;
+ }
+
+ return 0;
+}
+// パーティメッセージ送信
+int party_send_message(struct map_session_data *sd,char *mes,int len)
+{
+ if(sd->status.party_id==0)
+ return 0;
+ intif_party_message(sd->status.party_id,sd->status.account_id,mes,len);
+ return 0;
+}
+
+// パーティメッセージ受信
+int party_recv_message(int party_id,int account_id,char *mes,int len)
+{
+ struct party *p;
+ if( (p=party_search(party_id))==NULL)
+ return 0;
+ clif_party_message(p,account_id,mes,len);
+ return 0;
+}
+// パーティ競合確認
+int party_check_conflict(struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+
+ intif_party_checkconflict(sd->status.party_id,sd->status.account_id,sd->status.name);
+ return 0;
+}
+
+
+// 位置やHP通知用
+int party_send_xyhp_timer_sub(void *key,void *data,va_list ap)
+{
+ struct party *p=(struct party *)data;
+ int i;
+
+ nullpo_retr(0, p);
+
+ for(i=0;i<MAX_PARTY;i++){
+ struct map_session_data *sd;
+ if((sd=p->member[i].sd)!=NULL){
+ // 座標通知
+ if(sd->party_x!=sd->bl.x || sd->party_y!=sd->bl.y){
+ clif_party_xy(p,sd);
+ sd->party_x=sd->bl.x;
+ sd->party_y=sd->bl.y;
+ }
+ // HP通知
+ if(sd->party_hp!=sd->status.hp){
+ clif_party_hp(p,sd);
+ sd->party_hp=sd->status.hp;
+ }
+
+ }
+ }
+ return 0;
+}
+// 位置やHP通知
+int party_send_xyhp_timer(int tid,unsigned int tick,int id,int data)
+{
+ numdb_foreach(party_db,party_send_xyhp_timer_sub,tick);
+ return 0;
+}
+
+// 位置通知クリア
+int party_send_xy_clear(struct party *p)
+{
+ int i;
+
+ nullpo_retr(0, p);
+
+ for(i=0;i<MAX_PARTY;i++){
+ struct map_session_data *sd;
+ if((sd=p->member[i].sd)!=NULL){
+ sd->party_x=-1;
+ sd->party_y=-1;
+ sd->party_hp=-1;
+ }
+ }
+ return 0;
+}
+// HP通知の必要性検査用(map_foreachinmoveareaから呼ばれる)
+int party_send_hp_check(struct block_list *bl,va_list ap)
+{
+ int party_id;
+ int *flag;
+ struct map_session_data *sd;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, sd=(struct map_session_data *)bl);
+
+ party_id=va_arg(ap,int);
+ flag=va_arg(ap,int *);
+
+ if(sd->status.party_id==party_id){
+ *flag=1;
+ sd->party_hp=-1;
+ }
+ return 0;
+}
+
+// 経験値公平分配
+int party_exp_share(struct party *p,int map,int base_exp,int job_exp)
+{
+ struct map_session_data *sd;
+ int i,c;
+
+ nullpo_retr(0, p);
+
+ for(i=c=0;i<MAX_PARTY;i++)
+ if((sd=p->member[i].sd)!=NULL && sd->bl.m==map)
+ c++;
+ if(c==0)
+ return 0;
+ for(i=0;i<MAX_PARTY;i++)
+ if((sd=p->member[i].sd)!=NULL && sd->bl.m==map)
+ pc_gainexp(sd,base_exp/c+1,job_exp/c+1);
+ return 0;
+}
+
+// 同じマップのパーティメンバー全体に処理をかける
+// type==0 同じマップ
+// !=0 画面内
+void party_foreachsamemap(int (*func)(struct block_list*,va_list),
+ struct map_session_data *sd,int type,...)
+{
+ struct party *p;
+ va_list ap;
+ int i;
+ int x0,y0,x1,y1;
+ struct block_list *list[MAX_PARTY];
+ int blockcount=0;
+
+ nullpo_retv(sd);
+
+ if((p=party_search(sd->status.party_id))==NULL)
+ return;
+
+ x0=sd->bl.x-AREA_SIZE;
+ y0=sd->bl.y-AREA_SIZE;
+ x1=sd->bl.x+AREA_SIZE;
+ y1=sd->bl.y+AREA_SIZE;
+
+ va_start(ap,type);
+
+ for(i=0;i<MAX_PARTY;i++){
+ struct party_member *m=&p->member[i];
+ if(m->sd!=NULL){
+ if(sd->bl.m!=m->sd->bl.m)
+ continue;
+ if(type!=0 &&
+ (m->sd->bl.x<x0 || m->sd->bl.y<y0 ||
+ m->sd->bl.x>x1 || m->sd->bl.y>y1 ) )
+ continue;
+ list[blockcount++]=&m->sd->bl;
+ }
+ }
+
+ map_freeblock_lock(); // メモリからの解放を禁止する
+
+ for(i=0;i<blockcount;i++)
+ if(list[i]->prev) // 有効かどうかチェック
+ func(list[i],ap);
+
+ map_freeblock_unlock(); // 解放を許可する
+
+ va_end(ap);
+}
diff --git a/src/map/party.h b/src/map/party.h
new file mode 100644
index 000000000..e1a03fcd1
--- /dev/null
+++ b/src/map/party.h
@@ -0,0 +1,47 @@
+// $Id: party.h,v 1.3 2004/09/25 05:32:18 MouseJstr Exp $
+#ifndef _PARTY_H_
+#define _PARTY_H_
+
+#include <stdarg.h>
+
+struct party;
+struct map_session_data;
+struct block_list;
+
+void do_init_party(void);
+void do_final_party(void);
+struct party *party_search(int party_id);
+struct party* party_searchname(char *str);
+
+int party_create(struct map_session_data *sd,char *name);
+int party_created(int account_id,int fail,int party_id,char *name);
+int party_request_info(int party_id);
+int party_invite(struct map_session_data *sd,int account_id);
+int party_member_added(int party_id,int account_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_leaved(int party_id,int account_id,char *name);
+int party_reply_invite(struct map_session_data *sd,int account_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,char *map,int online,int lv);
+int party_broken(int party_id);
+int party_optionchanged(int party_id,int account_id,int exp,int item,int flag);
+int party_changeoption(struct map_session_data *sd,int exp,int item);
+
+int party_send_movemap(struct map_session_data *sd);
+int party_send_logout(struct map_session_data *sd);
+
+int party_send_message(struct map_session_data *sd,char *mes,int len);
+int party_recv_message(int party_id,int account_id,char *mes,int len);
+
+int party_check_conflict(struct map_session_data *sd);
+
+int party_send_xy_clear(struct party *p);
+int party_send_hp_check(struct block_list *bl,va_list ap);
+
+int party_exp_share(struct party *p,int map,int base_exp,int job_exp);
+
+void party_foreachsamemap(int (*func)(struct block_list *,va_list),struct map_session_data *sd,int type,...);
+
+#endif
diff --git a/src/map/path.c b/src/map/path.c
new file mode 100644
index 000000000..51143c943
--- /dev/null
+++ b/src/map/path.c
@@ -0,0 +1,404 @@
+// $Id: path.c,v 1.1.1.1 2004/09/10 17:27:00 MagicalTux Exp $
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "map.h"
+#include "battle.h"
+#include "nullpo.h"
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+//#define PATH_STANDALONETEST
+
+#define MAX_HEAP 150
+struct tmp_path { short x,y,dist,before,cost; char dir,flag;};
+#define calc_index(x,y) (((x)+(y)*MAX_WALKPATH) & (MAX_WALKPATH*MAX_WALKPATH-1))
+
+/*==========================================
+ * 経路探索補助heap push
+ *------------------------------------------
+ */
+static void push_heap_path(int *heap,struct tmp_path *tp,int index)
+{
+ int i,h;
+
+ if( heap == NULL || tp == NULL ){
+ printf("push_heap_path nullpo\n");
+ return;
+ }
+
+ heap[0]++;
+
+ for(h=heap[0]-1,i=(h-1)/2;
+ h>0 && tp[index].cost<tp[heap[i+1]].cost;
+ i=(h-1)/2)
+ heap[h+1]=heap[i+1],h=i;
+ heap[h+1]=index;
+}
+
+/*==========================================
+ * 経路探索補助heap update
+ * costが減ったので根の方へ移動
+ *------------------------------------------
+ */
+static void update_heap_path(int *heap,struct tmp_path *tp,int index)
+{
+ int i,h;
+
+ nullpo_retv(heap);
+ nullpo_retv(tp);
+
+ for(h=0;h<heap[0];h++)
+ if(heap[h+1]==index)
+ break;
+ if(h==heap[0]){
+ fprintf(stderr,"update_heap_path bug\n");
+ exit(1);
+ }
+ for(i=(h-1)/2;
+ h>0 && tp[index].cost<tp[heap[i+1]].cost;
+ i=(h-1)/2)
+ heap[h+1]=heap[i+1],h=i;
+ heap[h+1]=index;
+}
+
+/*==========================================
+ * 経路探索補助heap pop
+ *------------------------------------------
+ */
+static int pop_heap_path(int *heap,struct tmp_path *tp)
+{
+ int i,h,k;
+ int ret,last;
+
+ nullpo_retr(-1, heap);
+ nullpo_retr(-1, tp);
+
+ if(heap[0]<=0)
+ return -1;
+ ret=heap[1];
+ last=heap[heap[0]];
+ heap[0]--;
+
+ for(h=0,k=2;k<heap[0];k=k*2+2){
+ if(tp[heap[k+1]].cost>tp[heap[k]].cost)
+ k--;
+ heap[h+1]=heap[k+1], h=k;
+ }
+ if(k==heap[0])
+ heap[h+1]=heap[k], h=k-1;
+
+ for(i=(h-1)/2;
+ h>0 && tp[heap[i+1]].cost>tp[last].cost;
+ i=(h-1)/2)
+ heap[h+1]=heap[i+1],h=i;
+ heap[h+1]=last;
+
+ return ret;
+}
+
+/*==========================================
+ * 現在の点のcost計算
+ *------------------------------------------
+ */
+static int calc_cost(struct tmp_path *p,int x1,int y1)
+{
+ int xd,yd;
+
+ nullpo_retr(0, p);
+
+ xd=x1-p->x;
+ if(xd<0) xd=-xd;
+ yd=y1-p->y;
+ if(yd<0) yd=-yd;
+ return (xd+yd)*10+p->dist;
+}
+
+/*==========================================
+ * 必要ならpathを追加/修正する
+ *------------------------------------------
+ */
+static int add_path(int *heap,struct tmp_path *tp,int x,int y,int dist,int dir,int before,int x1,int y1)
+{
+ int i;
+
+ nullpo_retr(0, heap);
+ nullpo_retr(0, tp);
+
+ i=calc_index(x,y);
+
+ if(tp[i].x==x && tp[i].y==y){
+ if(tp[i].dist>dist){
+ tp[i].dist=dist;
+ tp[i].dir=dir;
+ tp[i].before=before;
+ tp[i].cost=calc_cost(&tp[i],x1,y1);
+ if(tp[i].flag)
+ push_heap_path(heap,tp,i);
+ else
+ update_heap_path(heap,tp,i);
+ tp[i].flag=0;
+ }
+ return 0;
+ }
+
+ if(tp[i].x || tp[i].y)
+ return 1;
+
+ tp[i].x=x;
+ tp[i].y=y;
+ tp[i].dist=dist;
+ tp[i].dir=dir;
+ tp[i].before=before;
+ tp[i].cost=calc_cost(&tp[i],x1,y1);
+ tp[i].flag=0;
+ push_heap_path(heap,tp,i);
+
+ return 0;
+}
+
+
+/*==========================================
+ * (x,y)が移動不可能地帯かどうか
+ * flag 0x10000 遠距離攻撃判定
+ *------------------------------------------
+ */
+static int can_place(struct map_data *m,int x,int y,int flag)
+{
+ int c;
+
+ nullpo_retr(0, m);
+
+ c=read_gatp(m,x,y);
+
+ if(c==1)
+ return 0;
+ if(!(flag&0x10000) && c==5)
+ return 0;
+ return 1;
+}
+
+/*==========================================
+ * (x0,y0)から(x1,y1)へ1歩で移動可能か計算
+ *------------------------------------------
+ */
+static int can_move(struct map_data *m,int x0,int y0,int x1,int y1,int flag)
+{
+ nullpo_retr(0, m);
+
+ if(x0-x1<-1 || x0-x1>1 || y0-y1<-1 || y0-y1>1)
+ return 0;
+ if(x1<0 || y1<0 || x1>=m->xs || y1>=m->ys)
+ return 0;
+ if(!can_place(m,x0,y0,flag))
+ return 0;
+ if(!can_place(m,x1,y1,flag))
+ return 0;
+ if(x0==x1 || y0==y1)
+ return 1;
+ if(!can_place(m,x0,y1,flag) || !can_place(m,x1,y0,flag))
+ return 0;
+ return 1;
+}
+/*==========================================
+ * (x0,y0)から(dx,dy)方向へcountセル分
+ * 吹き飛ばしたあとの座標を所得
+ *------------------------------------------
+ */
+int path_blownpos(int m,int x0,int y0,int dx,int dy,int count)
+{
+ struct map_data *md;
+
+ if(!map[m].gat)
+ return -1;
+ md=&map[m];
+
+ if(count>15){ // 最大10マスに制限
+ if(battle_config.error_log)
+ printf("path_blownpos: count too many %d !\n",count);
+ count=15;
+ }
+ if(dx>1 || dx<-1 || dy>1 || dy<-1){
+ if(battle_config.error_log)
+ printf("path_blownpos: illeagal dx=%d or dy=%d !\n",dx,dy);
+ dx=(dx>=0)?1:((dx<0)?-1:0);
+ dy=(dy>=0)?1:((dy<0)?-1:0);
+ }
+
+ while( (count--)>0 && (dx!=0 || dy!=0) ){
+ if( !can_move(md,x0,y0,x0+dx,y0+dy,0) ){
+ int fx=(dx!=0 && can_move(md,x0,y0,x0+dx,y0,0));
+ int fy=(dy!=0 && can_move(md,x0,y0,x0,y0+dy,0));
+ if( fx && fy ){
+ if(rand()&1) dx=0;
+ else dy=0;
+ }
+ if( !fx ) dx=0;
+ if( !fy ) dy=0;
+ }
+ x0+=dx;
+ y0+=dy;
+ }
+ return (x0<<16)|y0;
+}
+
+/*==========================================
+ * path探索 (x0,y0)->(x1,y1)
+ *------------------------------------------
+ */
+int path_search(struct walkpath_data *wpd,int m,int x0,int y0,int x1,int y1,int flag)
+{
+ int heap[MAX_HEAP+1];
+ struct tmp_path tp[MAX_WALKPATH*MAX_WALKPATH];
+ int i,rp,x,y;
+ struct map_data *md;
+ int dx,dy;
+
+ nullpo_retr(0, wpd);
+
+ if(!map[m].gat)
+ return -1;
+ md=&map[m];
+ if(x1<0 || x1>=md->xs || y1<0 || y1>=md->ys || (i=read_gatp(md,x1,y1))==1 || i==5)
+ return -1;
+
+ // easy
+ dx = (x1-x0<0) ? -1 : 1;
+ dy = (y1-y0<0) ? -1 : 1;
+ for(x=x0,y=y0,i=0;x!=x1 || y!=y1;){
+ if(i>=sizeof(wpd->path))
+ return -1;
+ if(x!=x1 && y!=y1){
+ if(!can_move(md,x,y,x+dx,y+dy,flag))
+ break;
+ x+=dx;
+ y+=dy;
+ wpd->path[i++]=(dx<0) ? ((dy>0)? 1 : 3) : ((dy<0)? 5 : 7);
+ } else if(x!=x1){
+ if(!can_move(md,x,y,x+dx,y ,flag))
+ break;
+ x+=dx;
+ wpd->path[i++]=(dx<0) ? 2 : 6;
+ } else { // y!=y1
+ if(!can_move(md,x,y,x ,y+dy,flag))
+ break;
+ y+=dy;
+ wpd->path[i++]=(dy>0) ? 0 : 4;
+ }
+ if(x==x1 && y==y1){
+ wpd->path_len=i;
+ wpd->path_pos=0;
+ wpd->path_half=0;
+ return 0;
+ }
+ }
+ if(flag&1)
+ return -1;
+
+ memset(tp,0,sizeof(tp));
+
+ i=calc_index(x0,y0);
+ tp[i].x=x0;
+ tp[i].y=y0;
+ tp[i].dist=0;
+ tp[i].dir=0;
+ tp[i].before=0;
+ tp[i].cost=calc_cost(&tp[i],x1,y1);
+ tp[i].flag=0;
+ heap[0]=0;
+ push_heap_path(heap,tp,calc_index(x0,y0));
+ while(1){
+ int e=0,fromdir;
+
+ if(heap[0]==0)
+ return -1;
+ rp=pop_heap_path(heap,tp);
+ x=tp[rp].x;
+ y=tp[rp].y;
+ if(x==x1 && y==y1){
+ int len,j;
+
+ for(len=0,i=rp;len<100 && i!=calc_index(x0,y0);i=tp[i].before,len++);
+ if(len==100 || len>=sizeof(wpd->path))
+ return -1;
+ wpd->path_len=len;
+ wpd->path_pos=0;
+ wpd->path_half=0;
+ for(i=rp,j=len-1;j>=0;i=tp[i].before,j--)
+ wpd->path[j]=tp[i].dir;
+
+ return 0;
+ }
+ fromdir=tp[rp].dir;
+ if(can_move(md,x,y,x+1,y-1,flag))
+ e+=add_path(heap,tp,x+1,y-1,tp[rp].dist+14,5,rp,x1,y1);
+ if(can_move(md,x,y,x+1,y ,flag))
+ e+=add_path(heap,tp,x+1,y ,tp[rp].dist+10,6,rp,x1,y1);
+ if(can_move(md,x,y,x+1,y+1,flag))
+ e+=add_path(heap,tp,x+1,y+1,tp[rp].dist+14,7,rp,x1,y1);
+ if(can_move(md,x,y,x ,y+1,flag))
+ e+=add_path(heap,tp,x ,y+1,tp[rp].dist+10,0,rp,x1,y1);
+ if(can_move(md,x,y,x-1,y+1,flag))
+ e+=add_path(heap,tp,x-1,y+1,tp[rp].dist+14,1,rp,x1,y1);
+ if(can_move(md,x,y,x-1,y ,flag))
+ e+=add_path(heap,tp,x-1,y ,tp[rp].dist+10,2,rp,x1,y1);
+ if(can_move(md,x,y,x-1,y-1,flag))
+ e+=add_path(heap,tp,x-1,y-1,tp[rp].dist+14,3,rp,x1,y1);
+ if(can_move(md,x,y,x ,y-1,flag))
+ e+=add_path(heap,tp,x ,y-1,tp[rp].dist+10,4,rp,x1,y1);
+ tp[rp].flag=1;
+ if(e || heap[0]>=MAX_HEAP-5)
+ return -1;
+ }
+ return -1;
+}
+
+#ifdef PATH_STANDALONETEST
+char gat[64][64]={
+ {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,1,0,0,0,0,0},
+};
+struct map_data map[1];
+
+/*==========================================
+ * 経路探索ルーチン単体テスト用main関数
+ *------------------------------------------
+ */
+void main(int argc,char *argv[])
+{
+ struct walkpath_data wpd;
+
+ map[0].gat=gat;
+ map[0].xs=64;
+ map[0].ys=64;
+
+ path_search(&wpd,0,3,4,5,4);
+ path_search(&wpd,0,5,4,3,4);
+ path_search(&wpd,0,6,4,3,4);
+ path_search(&wpd,0,7,4,3,4);
+ path_search(&wpd,0,4,3,4,5);
+ path_search(&wpd,0,4,2,4,5);
+ path_search(&wpd,0,4,1,4,5);
+ path_search(&wpd,0,4,5,4,3);
+ path_search(&wpd,0,4,6,4,3);
+ path_search(&wpd,0,4,7,4,3);
+ path_search(&wpd,0,7,4,3,4);
+ path_search(&wpd,0,8,4,3,4);
+ path_search(&wpd,0,9,4,3,4);
+ path_search(&wpd,0,10,4,3,4);
+ path_search(&wpd,0,11,4,3,4);
+ path_search(&wpd,0,12,4,3,4);
+ path_search(&wpd,0,13,4,3,4);
+ path_search(&wpd,0,14,4,3,4);
+ path_search(&wpd,0,15,4,3,4);
+ path_search(&wpd,0,16,4,3,4);
+ path_search(&wpd,0,17,4,3,4);
+ path_search(&wpd,0,18,4,3,4);
+}
+#endif
diff --git a/src/map/pc.c b/src/map/pc.c
new file mode 100644
index 000000000..34a1e9c72
--- /dev/null
+++ b/src/map/pc.c
@@ -0,0 +1,7499 @@
+// $Id: pc.c 101 2004-09-25 17:57:22Z Valaris $
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "socket.h" // [Valaris]
+#include "timer.h"
+#include "db.h"
+
+#include "malloc.h"
+#include "map.h"
+#include "chrif.h"
+#include "clif.h"
+#include "intif.h"
+#include "pc.h"
+#include "npc.h"
+#include "mob.h"
+#include "pet.h"
+#include "itemdb.h"
+#include "script.h"
+#include "battle.h"
+#include "skill.h"
+#include "party.h"
+#include "guild.h"
+#include "chat.h"
+#include "trade.h"
+#include "storage.h"
+#include "vending.h"
+#include "nullpo.h"
+#include "atcommand.h"
+#include "log.h"
+
+#ifndef TXT_ONLY // mail system [Valaris]
+#include "mail.h"
+#endif
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+#define PVP_CALCRANK_INTERVAL 1000 // PVP順位計算の間隔
+
+#define STATE_BLIND 0x10
+
+static int max_weight_base[MAX_PC_CLASS];
+static int hp_coefficient[MAX_PC_CLASS];
+static int hp_coefficient2[MAX_PC_CLASS];
+static int hp_sigma_val[MAX_PC_CLASS][MAX_LEVEL];
+static int sp_coefficient[MAX_PC_CLASS];
+static int aspd_base[MAX_PC_CLASS][20];
+static char job_bonus[3][MAX_PC_CLASS][MAX_LEVEL];
+static int exp_table[14][MAX_LEVEL];
+static char statp[255][7];
+static struct {
+ int id;
+ int max;
+ struct {
+ short id,lv;
+ } need[6];
+} skill_tree[3][MAX_PC_CLASS][100];
+
+static int atkmods[3][20]; // 武器ATKサイズ修正(size_fix.txt)
+static int refinebonus[5][3]; // 精錬ボーナステーブル(refine_db.txt)
+static int percentrefinery[5][10]; // 精錬成功率(refine_db.txt)
+
+static int dirx[8]={0,-1,-1,-1,0,1,1,1};
+static int diry[8]={1,1,0,-1,-1,-1,0,1};
+
+static unsigned int equip_pos[11]={0x0080,0x0008,0x0040,0x0004,0x0001,0x0200,0x0100,0x0010,0x0020,0x0002,0x8000};
+
+//static struct dbt *gm_account_db;
+static struct gm_account *gm_account = NULL;
+static int GM_num = 0;
+
+int pc_isGM(struct map_session_data *sd) {
+// struct gm_account *p;
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if(sd->bl.type!=BL_PC )
+ return 0;
+
+/* p = numdb_search(gm_account_db, sd->status.account_id);
+ if (p == NULL)
+ return 0;
+ return p->level;*/
+
+ //For console [Wizputer]
+ if ( sd->fd == 0 )
+ return 99;
+
+ for(i = 0; i < GM_num; i++)
+ if (gm_account[i].account_id == sd->status.account_id)
+ return gm_account[i].level;
+ return 0;
+
+}
+
+int pc_iskiller(struct map_session_data *src, struct map_session_data *target) {
+ nullpo_retr(0, src);
+
+ if(src->bl.type!=BL_PC )
+ return 0;
+ if (src->special_state.killer)
+ return 1;
+
+ if(target->bl.type!=BL_PC )
+ return 0;
+ if (target->special_state.killable)
+ return 1;
+
+ return 0;
+}
+
+
+int pc_set_gm_level(int account_id, int level) {
+ int i;
+ for (i = 0; i < GM_num; i++) {
+ if (account_id == gm_account[i].account_id) {
+ gm_account[i].level = level;
+ return 0;
+ }
+ }
+
+ GM_num++;
+ gm_account = realloc(gm_account, sizeof(struct gm_account) * GM_num);
+ gm_account[GM_num - 1].account_id = account_id;
+ gm_account[GM_num - 1].level = level;
+ return 0;
+}
+
+int pc_getrefinebonus(int lv, int type) {
+ if (lv >= 0 && lv < 5 && type >= 0 && type < 3)
+ return refinebonus[lv][type];
+ return 0;
+}
+
+static int distance(int x0, int y0, int x1, int y1) {
+ int dx, dy;
+
+ dx = abs(x0-x1);
+ dy = abs(y0-y1);
+ return dx>dy ? dx : dy;
+}
+
+static int pc_invincible_timer(int tid,unsigned int tick,int id,int data) {
+ struct map_session_data *sd;
+
+ if( (sd=(struct map_session_data *)map_id2sd(id)) == NULL || sd->bl.type!=BL_PC )
+ return 1;
+
+ if(sd->invincible_timer != tid){
+ if(battle_config.error_log)
+ printf("invincible_timer %d != %d\n",sd->invincible_timer,tid);
+ return 0;
+ }
+ sd->invincible_timer=-1;
+
+ return 0;
+}
+
+int pc_setinvincibletimer(struct map_session_data *sd,int val) {
+ nullpo_retr(0, sd);
+
+ if(sd->invincible_timer != -1)
+ delete_timer(sd->invincible_timer,pc_invincible_timer);
+ sd->invincible_timer = add_timer(gettick()+val,pc_invincible_timer,sd->bl.id,0);
+ return 0;
+}
+
+int pc_delinvincibletimer(struct map_session_data *sd) {
+ nullpo_retr(0, sd);
+
+ if(sd->invincible_timer != -1) {
+ delete_timer(sd->invincible_timer,pc_invincible_timer);
+ sd->invincible_timer = -1;
+ }
+ return 0;
+}
+
+static int pc_spiritball_timer(int tid,unsigned int tick,int id,int data) {
+ struct map_session_data *sd;
+ int i;
+
+ if( (sd=(struct map_session_data *)map_id2sd(id)) == NULL || sd->bl.type!=BL_PC )
+ return 1;
+
+ if(sd->spirit_timer[0] != tid){
+ if(battle_config.error_log)
+ printf("spirit_timer %d != %d\n",sd->spirit_timer[0],tid);
+ return 0;
+ }
+ sd->spirit_timer[0]=-1;
+ for(i=1;i<sd->spiritball;i++) {
+ sd->spirit_timer[i-1] = sd->spirit_timer[i];
+ sd->spirit_timer[i] = -1;
+ }
+ sd->spiritball--;
+ if(sd->spiritball < 0)
+ sd->spiritball = 0;
+ clif_spiritball(sd);
+
+ return 0;
+}
+
+int pc_addspiritball(struct map_session_data *sd,int interval,int max) {
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if(max > MAX_SKILL_LEVEL)
+ max = MAX_SKILL_LEVEL;
+ if(sd->spiritball < 0)
+ sd->spiritball = 0;
+
+ if(sd->spiritball >= max) {
+ if(sd->spirit_timer[0] != -1) {
+ delete_timer(sd->spirit_timer[0],pc_spiritball_timer);
+ sd->spirit_timer[0] = -1;
+ }
+ for(i=1;i<max;i++) {
+ sd->spirit_timer[i-1] = sd->spirit_timer[i];
+ sd->spirit_timer[i] = -1;
+ }
+ }
+ else
+ sd->spiritball++;
+
+ sd->spirit_timer[sd->spiritball-1] = add_timer(gettick()+interval,pc_spiritball_timer,sd->bl.id,0);
+ clif_spiritball(sd);
+
+ return 0;
+}
+
+int pc_delspiritball(struct map_session_data *sd,int count,int type) {
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if(sd->spiritball <= 0) {
+ sd->spiritball = 0;
+ return 0;
+ }
+
+ if(count > sd->spiritball)
+ count = sd->spiritball;
+ sd->spiritball -= count;
+ if(count > MAX_SKILL_LEVEL)
+ count = MAX_SKILL_LEVEL;
+
+ for(i=0;i<count;i++) {
+ if(sd->spirit_timer[i] != -1) {
+ delete_timer(sd->spirit_timer[i],pc_spiritball_timer);
+ sd->spirit_timer[i] = -1;
+ }
+ }
+ for(i=count;i<MAX_SKILL_LEVEL;i++) {
+ sd->spirit_timer[i-count] = sd->spirit_timer[i];
+ sd->spirit_timer[i] = -1;
+ }
+
+ if(!type)
+ clif_spiritball(sd);
+
+ return 0;
+}
+
+int pc_setrestartvalue(struct map_session_data *sd,int type) {
+ //転生や養子の場合の元の職業を算出する
+ struct pc_base_job s_class;
+
+ nullpo_retr(0, sd);
+
+ s_class = pc_calc_base_job(sd->status.class);
+
+ //-----------------------
+ // 死亡した
+ if(sd->special_state.restart_full_recover) { // オシリスカード
+ sd->status.hp=sd->status.max_hp;
+ sd->status.sp=sd->status.max_sp;
+ }
+ else {
+ if(s_class.job == 0 && battle_config.restart_hp_rate < 50) { //ノビは半分回復
+ sd->status.hp=(sd->status.max_hp)/2;
+ }
+ else {
+ if(battle_config.restart_hp_rate <= 0)
+ sd->status.hp = 1;
+ else {
+ sd->status.hp = sd->status.max_hp * battle_config.restart_hp_rate /100;
+ if(sd->status.hp <= 0)
+ sd->status.hp = 1;
+ }
+ }
+ if(battle_config.restart_sp_rate > 0) {
+ int sp = sd->status.max_sp * battle_config.restart_sp_rate /100;
+ if(sd->status.sp < sp)
+ sd->status.sp = sp;
+ }
+ }
+ if(type&1)
+ clif_updatestatus(sd,SP_HP);
+ if(type&1)
+ clif_updatestatus(sd,SP_SP);
+
+ /* removed exp penalty on spawn [Valaris] */
+
+ if(type&2 && sd->status.class != 0 && battle_config.zeny_penalty > 0 && !map[sd->bl.m].flag.nozenypenalty) {
+ int zeny = (int)((double)sd->status.zeny * (double)battle_config.zeny_penalty / 10000.);
+ if(zeny < 1) zeny = 1;
+ sd->status.zeny -= zeny;
+ if(sd->status.zeny < 0) sd->status.zeny = 0;
+ clif_updatestatus(sd,SP_ZENY);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 自分をロックしているMOBの数を数える(foreachclient)
+ *------------------------------------------
+ */
+static int pc_counttargeted_sub(struct block_list *bl,va_list ap)
+{
+ int id,*c,target_lv;
+ struct block_list *src;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+
+ id=va_arg(ap,int);
+
+ nullpo_retr(0, c=va_arg(ap,int *));
+
+ src=va_arg(ap,struct block_list *);
+ target_lv=va_arg(ap,int);
+ if(id == bl->id || (src && id == src->id)) return 0;
+ if(bl->type == BL_PC) {
+ struct map_session_data *sd=(struct map_session_data *)bl;
+ if( sd && sd->attacktarget == id && sd->attacktimer != -1 && sd->attacktarget_lv >= target_lv)
+ (*c)++;
+ }
+ else if(bl->type == BL_MOB) {
+ struct mob_data *md = (struct mob_data *)bl;
+ if(md && md->target_id == id && md->timer != -1 && md->state.state == MS_ATTACK && md->target_lv >= target_lv)
+
+ (*c)++;
+ //printf("md->target_lv:%d, target_lv:%d\n",((struct mob_data *)bl)->target_lv,target_lv);
+ }
+ return 0;
+}
+
+int pc_counttargeted(struct map_session_data *sd,struct block_list *src,int target_lv)
+{
+ int c=0;
+ map_foreachinarea(pc_counttargeted_sub, sd->bl.m,
+ sd->bl.x-AREA_SIZE,sd->bl.y-AREA_SIZE,
+ sd->bl.x+AREA_SIZE,sd->bl.y+AREA_SIZE,0,sd->bl.id,&c,src,target_lv);
+ return c;
+}
+
+/*==========================================
+ * ローカルプロトタイプ宣言 (必要な物のみ)
+ *------------------------------------------
+ */
+static int pc_walktoxy_sub(struct map_session_data *);
+
+/*==========================================
+ * saveに必要なステータス修正を行なう
+ *------------------------------------------
+ */
+int pc_makesavestatus(struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+
+ // 服の色は色々弊害が多いので保存対象にはしない
+ if(!battle_config.save_clothcolor)
+ sd->status.clothes_color=0;
+
+ // 死亡状態だったのでhpを1、位置をセーブ場所に変更
+ if(pc_isdead(sd)){
+ pc_setrestartvalue(sd,0);
+ memcpy(&sd->status.last_point,&sd->status.save_point,sizeof(sd->status.last_point));
+ } else {
+ memcpy(sd->status.last_point.map,sd->mapname,24);
+ sd->status.last_point.x = sd->bl.x;
+ sd->status.last_point.y = sd->bl.y;
+ }
+
+ // セーブ禁止マップだったので指定位置に移動
+ if(map[sd->bl.m].flag.nosave){
+ struct map_data *m=&map[sd->bl.m];
+ if(strcmp(m->save.map,"SavePoint")==0)
+ memcpy(&sd->status.last_point,&sd->status.save_point,sizeof(sd->status.last_point));
+ else
+ memcpy(&sd->status.last_point,&m->save,sizeof(sd->status.last_point));
+ }
+
+ //マナーポイントがプラスだった場合0に
+ if(battle_config.muting_players && sd->status.manner > 0)
+ sd->status.manner = 0;
+ return 0;
+}
+
+/*==========================================
+ * 接続時の初期化
+ *------------------------------------------
+ */
+int pc_setnewpc(struct map_session_data *sd, int account_id, int char_id, int login_id1, int client_tick, int sex, int fd) {
+ nullpo_retr(0, sd);
+
+ sd->bl.id = account_id;
+ sd->char_id = char_id;
+ sd->login_id1 = login_id1;
+ sd->login_id2 = 0; // at this point, we can not know the value :(
+ sd->client_tick = client_tick;
+ sd->sex = sex;
+ sd->state.auth = 0;
+ sd->bl.type = BL_PC;
+ sd->canact_tick = sd->canmove_tick = gettick();
+ sd->canlog_tick = gettick();
+ sd->state.waitingdisconnect = 0;
+
+ return 0;
+}
+
+int pc_equippoint(struct map_session_data *sd,int n)
+{
+ int ep = 0;
+ //転生や養子の場合の元の職業を算出する
+ struct pc_base_job s_class;
+
+ nullpo_retr(0, sd);
+
+ s_class = pc_calc_base_job(sd->status.class);
+
+ if(sd->inventory_data[n]) {
+ ep = sd->inventory_data[n]->equip;
+ if(sd->inventory_data[n]->look == 1 || sd->inventory_data[n]->look == 2 || sd->inventory_data[n]->look == 6) {
+ if(ep == 2 && (pc_checkskill(sd,AS_LEFT) > 0 || s_class.job == 12))
+ return 34;
+ }
+ }
+ return ep;
+}
+
+int pc_setinventorydata(struct map_session_data *sd)
+{
+ int i,id;
+
+ nullpo_retr(0, sd);
+
+ for(i=0;i<MAX_INVENTORY;i++) {
+ id = sd->status.inventory[i].nameid;
+ sd->inventory_data[i] = itemdb_search(id);
+ }
+ return 0;
+}
+
+int pc_calcweapontype(struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+
+ if(sd->weapontype1 != 0 && sd->weapontype2 == 0)
+ sd->status.weapon = sd->weapontype1;
+ if(sd->weapontype1 == 0 && sd->weapontype2 != 0)// 左手武器 Only
+ sd->status.weapon = sd->weapontype2;
+ else if(sd->weapontype1 == 1 && sd->weapontype2 == 1)// 双短剣
+ sd->status.weapon = 0x11;
+ else if(sd->weapontype1 == 2 && sd->weapontype2 == 2)// 双単手剣
+ sd->status.weapon = 0x12;
+ else if(sd->weapontype1 == 6 && sd->weapontype2 == 6)// 双単手斧
+ sd->status.weapon = 0x13;
+ else if( (sd->weapontype1 == 1 && sd->weapontype2 == 2) ||
+ (sd->weapontype1 == 2 && sd->weapontype2 == 1) ) // 短剣 - 単手剣
+ sd->status.weapon = 0x14;
+ else if( (sd->weapontype1 == 1 && sd->weapontype2 == 6) ||
+ (sd->weapontype1 == 6 && sd->weapontype2 == 1) ) // 短剣 - 斧
+ sd->status.weapon = 0x15;
+ else if( (sd->weapontype1 == 2 && sd->weapontype2 == 6) ||
+ (sd->weapontype1 == 6 && sd->weapontype2 == 2) ) // 単手剣 - 斧
+ sd->status.weapon = 0x16;
+ else
+ sd->status.weapon = sd->weapontype1;
+
+ return 0;
+}
+
+int pc_setequipindex(struct map_session_data *sd)
+{
+ int i,j;
+
+ nullpo_retr(0, sd);
+
+ for(i=0;i<11;i++)
+ sd->equip_index[i] = -1;
+
+ for(i=0;i<MAX_INVENTORY;i++) {
+ if(sd->status.inventory[i].nameid <= 0)
+ continue;
+ if(sd->status.inventory[i].equip) {
+ for(j=0;j<11;j++)
+ if(sd->status.inventory[i].equip & equip_pos[j])
+ sd->equip_index[j] = i;
+ if(sd->status.inventory[i].equip & 0x0002) {
+ if(sd->inventory_data[i])
+ sd->weapontype1 = sd->inventory_data[i]->look;
+ else
+ sd->weapontype1 = 0;
+ }
+ if(sd->status.inventory[i].equip & 0x0020) {
+ if(sd->inventory_data[i]) {
+ if(sd->inventory_data[i]->type == 4) {
+ if(sd->status.inventory[i].equip == 0x0020)
+ sd->weapontype2 = sd->inventory_data[i]->look;
+ else
+ sd->weapontype2 = 0;
+ }
+ else
+ sd->weapontype2 = 0;
+ }
+ else
+ sd->weapontype2 = 0;
+ }
+ }
+ }
+ pc_calcweapontype(sd);
+
+ return 0;
+}
+
+int pc_isequip(struct map_session_data *sd,int n)
+{
+ struct item_data *item;
+ struct status_change *sc_data;
+ //転生や養子の場合の元の職業を算出する
+
+ nullpo_retr(0, sd);
+
+ item = sd->inventory_data[n];
+ sc_data = battle_get_sc_data(&sd->bl);
+ //s_class = pc_calc_base_job(sd->status.class);
+
+ if( battle_config.gm_allequip>0 && pc_isGM(sd)>=battle_config.gm_allequip )
+ return 1;
+
+ if(item == NULL)
+ return 0;
+ if(item->sex != 2 && sd->status.sex != item->sex)
+ return 0;
+ if(item->elv > 0 && sd->status.base_level < item->elv)
+ return 0;
+// -- moonsoul (below statement substituted for commented out version further below
+// as it allows all advanced classes to equip items their normal versions
+// could equip)
+//
+ if(((sd->status.class==13 || sd->status.class==4014) && ((1<<7)&item->class) == 0) || // have mounted classes use unmounted equipment [Valaris]
+ ((sd->status.class==21 || sd->status.class==4022) && ((1<<14)&item->class) == 0))
+ return 0;
+ if(sd->status.class!=13 && sd->status.class!=4014 && sd->status.class!=21 && sd->status.class!=4022)
+ if((sd->status.class<=4000 && ((1<<sd->status.class)&item->class) == 0) || (sd->status.class>4000 && sd->status.class<4023 && ((1<<(sd->status.class-4001))&item->class) == 0) ||
+ (sd->status.class>=4023 && ((1<<(sd->status.class-4023))&item->class) == 0))
+ return 0;
+// if(((1<<sd->status.class)&item->class) == 0)
+// return 0;
+ if(map[sd->bl.m].flag.pvp && (item->flag.no_equip==1 || item->flag.no_equip==3))
+ return 0;
+ if(map[sd->bl.m].flag.gvg && (item->flag.no_equip==2 || item->flag.no_equip==3))
+ return 0;
+ if(item->equip & 0x0002 && sc_data && sc_data[SC_STRIPWEAPON].timer != -1)
+ return 0;
+ if(item->equip & 0x0020 && sc_data && sc_data[SC_STRIPSHIELD].timer != -1)
+ return 0;
+ if(item->equip & 0x0010 && sc_data && sc_data[SC_STRIPARMOR].timer != -1)
+ return 0;
+ if(item->equip & 0x0100 && sc_data && sc_data[SC_STRIPHELM].timer != -1)
+ return 0;
+ return 1;
+}
+
+/*==========================================
+ * Weapon Breaking [Valaris]
+ *------------------------------------------
+ */
+int pc_breakweapon(struct map_session_data *sd)
+{
+ struct item_data* item;
+ char output[255];
+ int i;
+
+ if(sd==NULL)
+ return -1;
+ if(sd->unbreakable>=rand()%100)
+ return 0;
+ if(sd->sc_data && sd->sc_data[SC_CP_WEAPON].timer != -1)
+ return 0;
+
+ for(i=0;i<MAX_INVENTORY;i++){
+ if(sd->status.inventory[i].equip && sd->status.inventory[i].equip & 0x0002 && !sd->status.inventory[i].attribute==1){
+ item=sd->inventory_data[i];
+ sd->status.inventory[i].attribute=1;
+ pc_unequipitem(sd,i,0);
+ sprintf(output, "%s has broken.",item->jname);
+ clif_emotion(&sd->bl,23);
+ clif_displaymessage(sd->fd, output);
+ clif_equiplist(sd);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+/*==========================================
+ * Armor Breaking [Valaris]
+ *------------------------------------------
+ */
+int pc_breakarmor(struct map_session_data *sd)
+{
+ struct item_data* item;
+ char output[255];
+ int i;
+
+ if(sd==NULL)
+ return -1;
+ if(sd->unbreakable>=rand()%100)
+ return 0;
+ if(sd->sc_data && sd->sc_data[SC_CP_ARMOR].timer != -1)
+ return 0;
+
+ for(i=0;i<MAX_INVENTORY;i++){
+ if(sd->status.inventory[i].equip && sd->status.inventory[i].equip & 0x0010 && !sd->status.inventory[i].attribute==1){
+ item=sd->inventory_data[i];
+ sd->status.inventory[i].attribute=1;
+ pc_unequipitem(sd,i,0);
+ sprintf(output, "%s has broken.",item->jname);
+ clif_emotion(&sd->bl,23);
+ clif_displaymessage(sd->fd, output);
+ clif_equiplist(sd);
+ }
+ }
+
+ return 0;
+}
+/*==========================================
+ * session idに問題無し
+ * char鯖から送られてきたステータスを設定
+ *------------------------------------------
+ */
+int pc_authok(int id, int login_id2, time_t connect_until_time, struct mmo_charstatus *st)
+{
+ struct map_session_data *sd = NULL;
+
+ struct party *p;
+ struct guild *g;
+ int i;
+ unsigned long tick = gettick();
+
+ sd = map_id2sd(id);
+ if(sd==NULL)
+ return 1;
+
+ sd->login_id2 = login_id2;
+
+ memcpy(&sd->status, st, sizeof(*st));
+
+ if (sd->status.sex != sd->sex) {
+ clif_authfail_fd(sd->fd, 0);
+ return 1;
+ }
+
+ memset(&sd->state, 0, sizeof(sd->state));
+ // 基本的な初期化
+ sd->state.connect_new = 1;
+ sd->bl.prev = sd->bl.next = NULL;
+
+ sd->weapontype1 = sd->weapontype2 = 0;
+ sd->view_class = sd->status.class;
+ sd->speed = DEFAULT_WALK_SPEED;
+ sd->state.dead_sit = 0;
+ sd->dir = 0;
+ sd->head_dir = 0;
+ sd->state.auth = 1;
+ sd->walktimer = -1;
+ sd->attacktimer = -1;
+ sd->followtimer = -1; // [MouseJstr]
+ sd->skilltimer = -1;
+ sd->skillitem = -1;
+ sd->skillitemlv = -1;
+ sd->invincible_timer = -1;
+ sd->sg_count = 0;
+
+ sd->deal_locked = 0;
+ sd->trade_partner = 0;
+
+ sd->inchealhptick = 0;
+ sd->inchealsptick = 0;
+ sd->hp_sub = 0;
+ sd->sp_sub = 0;
+ sd->inchealspirithptick = 0;
+ sd->inchealspiritsptick = 0;
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ sd->attackabletime = tick;
+
+ sd->doridori_counter = 0;
+
+#ifndef TXT_ONLY // mail system [Valaris]
+ if(battle_config.mail_system)
+ sd->mail_counter = 0;
+#endif
+ sd->spiritball = 0;
+ for(i = 0; i < MAX_SKILL_LEVEL; i++)
+ sd->spirit_timer[i] = -1;
+ for(i = 0; i < MAX_SKILLTIMERSKILL; i++)
+ sd->skilltimerskill[i].timer = -1;
+
+ memset(&sd->dev,0,sizeof(struct square));
+ for(i = 0; i < 5; i++) {
+ sd->dev.val1[i] = 0;
+ sd->dev.val2[i] = 0;
+ }
+
+ // アカウント変数の送信要求
+ intif_request_accountreg(sd);
+
+ // アイテムチェック
+ pc_setinventorydata(sd);
+ pc_checkitem(sd);
+
+ // pet
+ sd->petDB = NULL;
+ sd->pd = NULL;
+ sd->pet_hungry_timer = -1;
+ memset(&sd->pet, 0, sizeof(struct s_pet));
+
+ // ステータス異常の初期化
+ for(i = 0; i < MAX_STATUSCHANGE; i++) {
+ sd->sc_data[i].timer=-1;
+ sd->sc_data[i].val1 = sd->sc_data[i].val2 = sd->sc_data[i].val3 = sd->sc_data[i].val4 = 0;
+ }
+ sd->sc_count=0;
+ if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) &&
+ (pc_isGM(sd) >= get_atcommand_level(AtCommand_Hide)))
+ sd->status.option &= (OPTION_MASK | OPTION_HIDE);
+ else
+ sd->status.option &= OPTION_MASK;
+
+ // スキルユニット関係の初期化
+ memset(sd->skillunit, 0, sizeof(sd->skillunit));
+ memset(sd->skillunittick, 0, sizeof(sd->skillunittick));
+
+ // パーティー関係の初期化
+ sd->party_sended = 0;
+ sd->party_invite = 0;
+ sd->party_x = -1;
+ sd->party_y = -1;
+ sd->party_hp = -1;
+
+ // ギルド関係の初期化
+ sd->guild_sended = 0;
+ sd->guild_invite = 0;
+ sd->guild_alliance = 0;
+
+ // イベント関係の初期化
+ memset(sd->eventqueue, 0, sizeof(sd->eventqueue));
+ for(i = 0; i < MAX_EVENTTIMER; i++)
+ sd->eventtimer[i] = -1;
+
+ // 位置の設定
+ pc_setpos(sd,sd->status.last_point.map, sd->status.last_point.x, sd->status.last_point.y, 0);
+
+ // pet
+ if (sd->status.pet_id > 0)
+ intif_request_petdata(sd->status.account_id, sd->status.char_id, sd->status.pet_id);
+
+ // パーティ、ギルドデータの要求
+ if (sd->status.party_id > 0 && (p = party_search(sd->status.party_id)) == NULL)
+ party_request_info(sd->status.party_id);
+ if (sd->status.guild_id > 0 && (g = guild_search(sd->status.guild_id)) == NULL)
+ guild_request_info(sd->status.guild_id);
+
+ // pvpの設定
+ sd->pvp_rank = 0;
+ sd->pvp_point = 0;
+ sd->pvp_timer = -1;
+
+ // 通知
+
+ clif_authok(sd);
+ map_addnickdb(sd);
+ if (map_charid2nick(sd->status.char_id) == NULL)
+ map_addchariddb(sd->status.char_id, sd->status.name);
+
+ //スパノビ用死にカウンターのスクリプト変数からの読み出しとsdへのセット
+ sd->die_counter = pc_readglobalreg(sd,"PC_DIE_COUNTER");
+
+ if (night_flag == 1) {
+ char tmpstr[1024];
+ strcpy(tmpstr, msg_txt(500)); // Actually, it's the night...
+ clif_wis_message(sd->fd, wisp_server_name, tmpstr, strlen(tmpstr)+1);
+ sd->opt2 |= STATE_BLIND;
+ }
+
+ // ステータス初期計算など
+ pc_calcstatus(sd,1);
+
+ if (pc_isGM(sd))
+ printf("Connection accepted: character '%s' (account: %d; GM level %d).\n", sd->status.name, sd->status.account_id, pc_isGM(sd));
+ else
+ printf("Connection accepted: Character '%s' (account: %d).\n", sd->status.name, sd->status.account_id);
+
+ //printf("pc: OnPCLogin event done. (%d events)\n", npc_event_doall("OnPCLogin") );
+ if (npc_name2id("PCLoginEvent"))
+ run_script(npc_name2id("PCLoginEvent")->u.scr.script,0,sd->bl.id,npc_name2id("PCLoginEvent")->bl.id); // PCLoginNPC
+ // Send friends list
+ clif_friends_list_send(sd);
+
+ // Message of the Dayの送信
+ {
+ char buf[256];
+ FILE *fp;
+ if ((fp = fopen(motd_txt, "r")) != NULL) {
+ while (fgets(buf, sizeof(buf)-1, fp) != NULL) {
+ int i;
+ for(i=0; buf[i]; i++) {
+ if (buf[i] == '\r' || buf[i]== '\n') {
+ buf[i] = 0;
+ break;
+ }
+ }
+ clif_displaymessage(sd->fd, buf);
+ }
+ fclose(fp);
+ }
+ }
+
+#ifndef TXT_ONLY
+ if(battle_config.mail_system)
+ mail_check(sd,1); // check mail at login [Valaris]
+#endif
+
+ // message of the limited time of the account
+ if (connect_until_time != 0) { // don't display if it's unlimited or unknow value
+ char tmpstr[1024];
+ strftime(tmpstr, sizeof(tmpstr) - 1, msg_txt(501), localtime(&connect_until_time)); // "Your account time limit is: %d-%m-%Y %H:%M:%S."
+ clif_wis_message(sd->fd, wisp_server_name, tmpstr, strlen(tmpstr)+1);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * session idに問題ありなので後始末
+ *------------------------------------------
+ */
+int pc_authfail(int id) {
+ struct map_session_data *sd;
+
+ sd = map_id2sd(id);
+ if (sd == NULL)
+ return 1;
+
+ clif_authfail_fd(sd->fd, 0);
+
+ return 0;
+}
+
+static int pc_calc_skillpoint(struct map_session_data* sd)
+{
+ int i,skill,skill_point=0;
+
+ nullpo_retr(0, sd);
+
+ for(i=1;i<MAX_SKILL;i++){
+ if( (skill = pc_checkskill(sd,i)) > 0) {
+ if(!(skill_get_inf2(i)&0x01) || battle_config.quest_skill_learn) {
+ if(!sd->status.skill[i].flag)
+ 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);
+ }
+ }
+ }
+ }
+
+ return skill_point;
+}
+
+/*==========================================
+ * 覚えられるスキルの計算
+ *------------------------------------------
+ */
+int pc_calc_skilltree(struct map_session_data *sd)
+{
+ int i,id=0,flag;
+ int c=0, s=0;
+ //転生や養子の場合の元の職業を算出する
+ struct pc_base_job s_class;
+
+ nullpo_retr(0, sd);
+
+ s_class = pc_calc_base_job(sd->status.class);
+ c = s_class.job;
+ s = (s_class.upper==1) ? 1 : 0 ; //転生以外は通常のスキル?
+
+ if((battle_config.skillup_limit) && ((c >= 0 && c < 23) || (c >= 4001 && c < 4023) || (c >= 4023 && c < 4045))) {
+ int skill_point = pc_calc_skillpoint(sd);
+ if(skill_point < 9)
+ c = 0;
+ else if((sd->status.skill_point >= sd->status.job_level && skill_point < 58) && ((c > 6 && c < 23) || (c > 4007 && c < 4023) || (c > 4029 && c < 4045))) {
+ switch(c) {
+ case 7:
+ case 14:
+ c = 1;
+ break;
+ case 8:
+ case 15:
+ c = 4;
+ break;
+ case 9:
+ case 16:
+ c = 2;
+ break;
+ case 10:
+ case 18:
+ c = 5;
+ break;
+ case 11:
+ case 19:
+ case 20:
+ c = 3;
+ break;
+ case 12:
+ case 17:
+ c = 6;
+ break;
+ case 4008:
+ case 4015:
+ c = 4002;
+ break;
+ case 4009:
+ case 4016:
+ c = 4005;
+ break;
+ case 4010:
+ case 4017:
+ c = 4003;
+ break;
+ case 4011:
+ case 4019:
+ c = 4006;
+ break;
+ case 4012:
+ case 4020:
+ case 4021:
+ c = 4004;
+ break;
+ case 4013:
+ case 4018:
+ c = 4007;
+ break;
+ case 4030:
+ case 4037:
+ c = 4024;
+ break;
+ case 4031:
+ case 4038:
+ c = 4027;
+ break;
+ case 4032:
+ case 4039:
+ c = 4025;
+ break;
+ case 4033:
+ case 4040:
+ c = 4028;
+ break;
+ case 4034:
+ case 4041:
+ case 4042:
+ c = 4026;
+ break;
+ case 4035:
+ case 4043:
+ c = 4029;
+ break;
+
+ }
+ }
+ }
+
+ for(i=0;i<MAX_SKILL;i++){
+ if (sd->status.skill[i].flag != 13) sd->status.skill[i].id=0;
+ if (sd->status.skill[i].flag && sd->status.skill[i].flag != 13){ // cardスキルなら、
+ sd->status.skill[i].lv=(sd->status.skill[i].flag==1)?0:sd->status.skill[i].flag-2; // 本当のlvに
+ sd->status.skill[i].flag=0; // flagは0にしておく
+ }
+ }
+
+ if (battle_config.gm_allskill > 0 && pc_isGM(sd) >= battle_config.gm_allskill){
+ // 全てのスキル
+ for(i=1;i<158;i++)
+ sd->status.skill[i].id=i;
+ for(i=210;i<291;i++)
+ sd->status.skill[i].id=i;
+ for(i=304;i<337;i++){
+ if(i==331) continue;
+ sd->status.skill[i].id=i;
+ }
+ if(battle_config.enable_upper_class){ //confで無効でなければ読み込む
+ for(i=355;i<MAX_SKILL;i++)
+ sd->status.skill[i].id=i;
+ }
+ }else{
+ // 通常の計算
+ do{
+ flag=0;
+ for(i=0;(id=skill_tree[s][c][i].id)>0;i++){
+ int j,f=1;
+ if(!battle_config.skillfree) {
+ for(j=0;j<5;j++) {
+ if( skill_tree[s][c][i].need[j].id &&
+ pc_checkskill(sd,skill_tree[s][c][i].need[j].id) < skill_tree[s][c][i].need[j].lv)
+ f=0;
+ }
+ }
+ if(f && sd->status.skill[id].id==0 ){
+ sd->status.skill[id].id=id;
+ flag=1;
+ }
+ }
+ }while(flag);
+ }
+// if(battle_config.etc_log)
+// printf("calc skill_tree\n");
+ return 0;
+}
+
+/*==========================================
+ * 重量アイコンの確認
+ *------------------------------------------
+ */
+int pc_checkweighticon(struct map_session_data *sd)
+{
+ int flag=0;
+
+ nullpo_retr(0, sd);
+
+ if(sd->weight*2 >= sd->max_weight)
+ flag=1;
+ if(sd->weight*10 >= sd->max_weight*9)
+ flag=2;
+
+ if(flag==1){
+ if(sd->sc_data[SC_WEIGHT50].timer==-1)
+ skill_status_change_start(&sd->bl,SC_WEIGHT50,0,0,0,0,0,0);
+ }else{
+ skill_status_change_end(&sd->bl,SC_WEIGHT50,-1);
+ }
+ if(flag==2){
+ if(sd->sc_data[SC_WEIGHT90].timer==-1)
+ skill_status_change_start(&sd->bl,SC_WEIGHT90,0,0,0,0,0,0);
+ }else{
+ skill_status_change_end(&sd->bl,SC_WEIGHT90,-1);
+ }
+ return 0;
+}
+
+/*==========================================
+ * パラメータ計算
+ * first==0の時、計算対象のパラメータが呼び出し前から
+ * 変 化した場合自動でsendするが、
+ * 能動的に変化させたパラメータは自前でsendするように
+ *------------------------------------------
+ */
+int pc_calcstatus(struct map_session_data* sd,int first)
+{
+ int b_speed,b_max_hp,b_max_sp,b_hp,b_sp,b_weight,b_max_weight,b_paramb[6],b_parame[6],b_hit,b_flee;
+ int b_aspd,b_watk,b_def,b_watk2,b_def2,b_flee2,b_critical,b_attackrange,b_matk1,b_matk2,b_mdef,b_mdef2,b_class;
+ int b_base_atk;
+ struct skill b_skill[MAX_SKILL];
+ int i,bl,index;
+ int skill,aspd_rate,wele,wele_,def_ele,refinedef=0;
+ int pele=0,pdef_ele=0;
+ int str,dstr,dex;
+ struct pc_base_job s_class;
+
+ nullpo_retr(0, sd);
+
+ //転生や養子の場合の元の職業を算出する
+ s_class = pc_calc_base_job(sd->status.class);
+
+ b_speed = sd->speed;
+ b_max_hp = sd->status.max_hp;
+ b_max_sp = sd->status.max_sp;
+ b_hp = sd->status.hp;
+ b_sp = sd->status.sp;
+ b_weight = sd->weight;
+ b_max_weight = sd->max_weight;
+ memcpy(b_paramb,&sd->paramb,sizeof(b_paramb));
+ memcpy(b_parame,&sd->paramc,sizeof(b_parame));
+ memcpy(b_skill,&sd->status.skill,sizeof(b_skill));
+ b_hit = sd->hit;
+ b_flee = sd->flee;
+ b_aspd = sd->aspd;
+ b_watk = sd->watk;
+ b_def = sd->def;
+ b_watk2 = sd->watk2;
+ b_def2 = sd->def2;
+ b_flee2 = sd->flee2;
+ b_critical = sd->critical;
+ b_attackrange = sd->attackrange;
+ b_matk1 = sd->matk1;
+ b_matk2 = sd->matk2;
+ b_mdef = sd->mdef;
+ b_mdef2 = sd->mdef2;
+ b_class = sd->view_class;
+ sd->view_class = sd->status.class;
+ b_base_atk = sd->base_atk;
+
+ pc_calc_skilltree(sd); // スキルツリーの計算
+
+ sd->max_weight = max_weight_base[s_class.job]+sd->status.str*300;
+
+ if(first&1) {
+ sd->weight=0;
+ for(i=0;i<MAX_INVENTORY;i++){
+ if(sd->status.inventory[i].nameid==0 || sd->inventory_data[i] == NULL)
+ continue;
+ sd->weight += sd->inventory_data[i]->weight*sd->status.inventory[i].amount;
+ }
+ sd->cart_max_weight=battle_config.max_cart_weight;
+ sd->cart_weight=0;
+ sd->cart_max_num=MAX_CART;
+ sd->cart_num=0;
+ for(i=0;i<MAX_CART;i++){
+ if(sd->status.cart[i].nameid==0)
+ continue;
+ sd->cart_weight+=itemdb_weight(sd->status.cart[i].nameid)*sd->status.cart[i].amount;
+ sd->cart_num++;
+ }
+ }
+
+ memset(sd->paramb,0,sizeof(sd->paramb));
+ memset(sd->parame,0,sizeof(sd->parame));
+ sd->hit = 0;
+ sd->flee = 0;
+ sd->flee2 = 0;
+ sd->critical = 0;
+ sd->aspd = 0;
+ sd->watk = 0;
+ sd->def = 0;
+ sd->mdef = 0;
+ sd->watk2 = 0;
+ sd->def2 = 0;
+ sd->mdef2 = 0;
+ sd->status.max_hp = 0;
+ sd->status.max_sp = 0;
+ sd->attackrange = 0;
+ sd->attackrange_ = 0;
+ sd->atk_ele = 0;
+ sd->def_ele = 0;
+ sd->star =0;
+ sd->overrefine =0;
+ sd->matk1 =0;
+ sd->matk2 =0;
+ sd->speed = DEFAULT_WALK_SPEED ;
+ sd->hprate=100;
+ sd->sprate=100;
+ sd->castrate=100;
+ sd->dsprate=100;
+ sd->base_atk=0;
+ sd->arrow_atk=0;
+ sd->arrow_ele=0;
+ sd->arrow_hit=0;
+ sd->arrow_range=0;
+ sd->nhealhp=sd->nhealsp=sd->nshealhp=sd->nshealsp=sd->nsshealhp=sd->nsshealsp=0;
+ memset(sd->addele,0,sizeof(sd->addele));
+ memset(sd->addrace,0,sizeof(sd->addrace));
+ memset(sd->addsize,0,sizeof(sd->addsize));
+ memset(sd->addele_,0,sizeof(sd->addele_));
+ memset(sd->addrace_,0,sizeof(sd->addrace_));
+ memset(sd->addsize_,0,sizeof(sd->addsize_));
+ memset(sd->subele,0,sizeof(sd->subele));
+ memset(sd->subrace,0,sizeof(sd->subrace));
+ memset(sd->addeff,0,sizeof(sd->addeff));
+ memset(sd->addeff2,0,sizeof(sd->addeff2));
+ memset(sd->reseff,0,sizeof(sd->reseff));
+ memset(&sd->special_state,0,sizeof(sd->special_state));
+ memset(sd->weapon_coma_ele,0,sizeof(sd->weapon_coma_ele));
+ memset(sd->weapon_coma_race,0,sizeof(sd->weapon_coma_race));
+
+ sd->watk_ = 0; //二刀流用(仮)
+ sd->watk_2 = 0;
+ sd->atk_ele_ = 0;
+ sd->star_ = 0;
+ sd->overrefine_ = 0;
+
+ sd->aspd_rate = 100;
+ sd->speed_rate = 100;
+ sd->hprecov_rate = 100;
+ sd->sprecov_rate = 100;
+ sd->critical_def = 0;
+ sd->double_rate = 0;
+ sd->near_attack_def_rate = sd->long_attack_def_rate = 0;
+ sd->atk_rate = sd->matk_rate = 100;
+ sd->ignore_def_ele = sd->ignore_def_race = 0;
+ sd->ignore_def_ele_ = sd->ignore_def_race_ = 0;
+ sd->ignore_mdef_ele = sd->ignore_mdef_race = 0;
+ sd->arrow_cri = 0;
+ sd->magic_def_rate = sd->misc_def_rate = 0;
+ memset(sd->arrow_addele,0,sizeof(sd->arrow_addele));
+ memset(sd->arrow_addrace,0,sizeof(sd->arrow_addrace));
+ memset(sd->arrow_addsize,0,sizeof(sd->arrow_addsize));
+ memset(sd->arrow_addeff,0,sizeof(sd->arrow_addeff));
+ memset(sd->arrow_addeff2,0,sizeof(sd->arrow_addeff2));
+ memset(sd->magic_addele,0,sizeof(sd->magic_addele));
+ memset(sd->magic_addrace,0,sizeof(sd->magic_addrace));
+ memset(sd->magic_subrace,0,sizeof(sd->magic_subrace));
+ sd->perfect_hit = 0;
+ sd->critical_rate = sd->hit_rate = sd->flee_rate = sd->flee2_rate = 100;
+ sd->def_rate = sd->def2_rate = sd->mdef_rate = sd->mdef2_rate = 100;
+ sd->def_ratio_atk_ele = sd->def_ratio_atk_ele_ = 0;
+ sd->def_ratio_atk_race = sd->def_ratio_atk_race_ = 0;
+ sd->get_zeny_num = 0;
+ sd->add_damage_class_count = sd->add_damage_class_count_ = sd->add_magic_damage_class_count = 0;
+ sd->add_def_class_count = sd->add_mdef_class_count = 0;
+ sd->monster_drop_item_count = 0;
+ memset(sd->add_damage_classrate,0,sizeof(sd->add_damage_classrate));
+ memset(sd->add_damage_classrate_,0,sizeof(sd->add_damage_classrate_));
+ memset(sd->add_magic_damage_classrate,0,sizeof(sd->add_magic_damage_classrate));
+ memset(sd->add_def_classrate,0,sizeof(sd->add_def_classrate));
+ memset(sd->add_mdef_classrate,0,sizeof(sd->add_mdef_classrate));
+ memset(sd->monster_drop_race,0,sizeof(sd->monster_drop_race));
+ memset(sd->monster_drop_itemrate,0,sizeof(sd->monster_drop_itemrate));
+ sd->speed_add_rate = sd->aspd_add_rate = 100;
+ sd->double_add_rate = sd->perfect_hit_add = sd->get_zeny_add_num = 0;
+ sd->splash_range = sd->splash_add_range = 0;
+ sd->autospell_id = sd->autospell_lv = sd->autospell_rate = 0;
+ sd->hp_drain_rate = sd->hp_drain_per = sd->sp_drain_rate = sd->sp_drain_per = 0;
+ sd->hp_drain_rate_ = sd->hp_drain_per_ = sd->sp_drain_rate_ = sd->sp_drain_per_ = 0;
+ sd->short_weapon_damage_return = sd->long_weapon_damage_return = 0;
+ sd->magic_damage_return = 0; //AppleGirl Was Here
+ sd->random_attack_increase_add = sd->random_attack_increase_per = 0;
+
+ if(!sd->disguiseflag && sd->disguise) {
+ sd->disguise=0;
+ clif_changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon);
+ clif_changelook(&sd->bl,LOOK_SHIELD,sd->status.shield);
+ clif_changelook(&sd->bl,LOOK_HEAD_BOTTOM,sd->status.head_bottom);
+ clif_changelook(&sd->bl,LOOK_HEAD_TOP,sd->status.head_top);
+ clif_changelook(&sd->bl,LOOK_HEAD_MID,sd->status.head_mid);
+ clif_clearchar(&sd->bl, 9);
+ pc_setpos(sd, sd->mapname, sd->bl.x, sd->bl.y, 3);
+ }
+
+ for(i=0;i<10;i++) {
+ index = sd->equip_index[i];
+ if(index < 0)
+ continue;
+ if(i == 9 && sd->equip_index[8] == index)
+ continue;
+ if(i == 5 && sd->equip_index[4] == index)
+ continue;
+ if(i == 6 && (sd->equip_index[5] == index || sd->equip_index[4] == index))
+ continue;
+
+ if(sd->inventory_data[index]) {
+ if(sd->inventory_data[index]->type == 4) {
+ if(sd->status.inventory[index].card[0]!=0x00ff && sd->status.inventory[index].card[0]!=0x00fe && sd->status.inventory[index].card[0]!=(short)0xff00) {
+ int j;
+ for(j=0;j<sd->inventory_data[index]->slot;j++){ // カード
+ int c=sd->status.inventory[index].card[j];
+ if(c>0){
+ if(i == 8 && sd->status.inventory[index].equip == 0x20)
+ sd->state.lr_flag = 1;
+ run_script(itemdb_equipscript(c),0,sd->bl.id,0);
+ sd->state.lr_flag = 0;
+ }
+ }
+ }
+ }
+ else if(sd->inventory_data[index]->type==5){ // 防具
+ if(sd->status.inventory[index].card[0]!=0x00ff && sd->status.inventory[index].card[0]!=0x00fe && sd->status.inventory[index].card[0]!=(short)0xff00) {
+ int j;
+ for(j=0;j<sd->inventory_data[index]->slot;j++){ // カード
+ int c=sd->status.inventory[index].card[j];
+ if(c>0)
+ run_script(itemdb_equipscript(c),0,sd->bl.id,0);
+ }
+ }
+ }
+ }
+ }
+ wele = sd->atk_ele;
+ wele_ = sd->atk_ele_;
+ def_ele = sd->def_ele;
+ if(sd->status.pet_id > 0) {
+ struct pet_data *pd=sd->pd;
+ if((pd && battle_config.pet_status_support==1) && (battle_config.pet_equip_required==0 || (battle_config.pet_equip_required && pd->equip > 0))) {
+ if(sd->status.pet_id > 0 && sd->petDB && sd->pet.intimate > 0)
+ run_script(sd->petDB->script,0,sd->bl.id,0);
+ pele = sd->atk_ele;
+ pdef_ele = sd->def_ele;
+ sd->atk_ele = sd->def_ele = 0;
+ }
+ }
+ memcpy(sd->paramcard,sd->parame,sizeof(sd->paramcard));
+
+ // 装備品によるステータス変化はここで実行
+ for(i=0;i<10;i++) {
+ index = sd->equip_index[i];
+ if(index < 0)
+ continue;
+ if(i == 9 && sd->equip_index[8] == index)
+ continue;
+ if(i == 5 && sd->equip_index[4] == index)
+ continue;
+ if(i == 6 && (sd->equip_index[5] == index || sd->equip_index[4] == index))
+ continue;
+ if(sd->inventory_data[index]) {
+ sd->def += sd->inventory_data[index]->def;
+ if(sd->inventory_data[index]->type == 4) {
+ int r,wlv = sd->inventory_data[index]->wlv;
+ if(i == 8 && sd->status.inventory[index].equip == 0x20) {
+ //二刀流用データ入力
+ sd->watk_ += sd->inventory_data[index]->atk;
+ sd->watk_2 = (r=sd->status.inventory[index].refine)* // 精錬攻撃力
+ refinebonus[wlv][0];
+ if( (r-=refinebonus[wlv][2])>0 ) // 過剰精錬ボーナス
+ sd->overrefine_ = r*refinebonus[wlv][1];
+
+ if(sd->status.inventory[index].card[0]==0x00ff){ // 製造武器
+ sd->star_ = (sd->status.inventory[index].card[1]>>8); // 星のかけら
+ wele_= (sd->status.inventory[index].card[1]&0x0f); // 属 性
+ }
+ sd->attackrange_ += sd->inventory_data[index]->range;
+ sd->state.lr_flag = 1;
+ run_script(sd->inventory_data[index]->equip_script,0,sd->bl.id,0);
+ sd->state.lr_flag = 0;
+ }
+ else { //二刀流武器以外
+ sd->watk += sd->inventory_data[index]->atk;
+ sd->watk2 += (r=sd->status.inventory[index].refine)* // 精錬攻撃力
+ refinebonus[wlv][0];
+ if( (r-=refinebonus[wlv][2])>0 ) // 過剰精錬ボーナス
+ sd->overrefine += r*refinebonus[wlv][1];
+
+ if(sd->status.inventory[index].card[0]==0x00ff){ // 製造武器
+ sd->star += (sd->status.inventory[index].card[1]>>8); // 星のかけら
+ wele = (sd->status.inventory[index].card[1]&0x0f); // 属 性
+ }
+ sd->attackrange += sd->inventory_data[index]->range;
+ run_script(sd->inventory_data[index]->equip_script,0,sd->bl.id,0);
+ }
+ }
+ else if(sd->inventory_data[index]->type == 5) {
+ sd->watk += sd->inventory_data[index]->atk;
+ refinedef += sd->status.inventory[index].refine*refinebonus[0][0];
+ run_script(sd->inventory_data[index]->equip_script,0,sd->bl.id,0);
+ }
+ }
+ }
+
+ if(sd->equip_index[10] >= 0){ // 矢
+ index = sd->equip_index[10];
+ if(sd->inventory_data[index]){ //まだ属性が入っていない
+ sd->state.lr_flag = 2;
+ run_script(sd->inventory_data[index]->equip_script,0,sd->bl.id,0);
+ sd->state.lr_flag = 0;
+ sd->arrow_atk += sd->inventory_data[index]->atk;
+ }
+ }
+ sd->def += (refinedef+50)/100;
+
+ if(sd->attackrange < 1) sd->attackrange = 1;
+ if(sd->attackrange_ < 1) sd->attackrange_ = 1;
+ if(sd->attackrange < sd->attackrange_)
+ sd->attackrange = sd->attackrange_;
+ if(sd->status.weapon == 11)
+ sd->attackrange += sd->arrow_range;
+ if(wele > 0)
+ sd->atk_ele = wele;
+ if(wele_ > 0)
+ sd->atk_ele_ = wele_;
+ if(def_ele > 0)
+ sd->def_ele = def_ele;
+ if(battle_config.pet_status_support) {
+ if(pele > 0 && !sd->atk_ele)
+ sd->atk_ele = pele;
+ if(pdef_ele > 0 && !sd->def_ele)
+ sd->def_ele = pdef_ele;
+ }
+ sd->double_rate += sd->double_add_rate;
+ sd->perfect_hit += sd->perfect_hit_add;
+ sd->get_zeny_num += sd->get_zeny_add_num;
+ sd->splash_range += sd->splash_add_range;
+ if(sd->speed_add_rate != 100)
+ sd->speed_rate += sd->speed_add_rate - 100;
+ if(sd->aspd_add_rate != 100)
+ sd->aspd_rate += sd->aspd_add_rate - 100;
+
+ // 武器ATKサイズ補正 (右手)
+ sd->atkmods[0] = atkmods[0][sd->weapontype1];
+ sd->atkmods[1] = atkmods[1][sd->weapontype1];
+ sd->atkmods[2] = atkmods[2][sd->weapontype1];
+ //武器ATKサイズ補正 (左手)
+ sd->atkmods_[0] = atkmods[0][sd->weapontype2];
+ sd->atkmods_[1] = atkmods[1][sd->weapontype2];
+ sd->atkmods_[2] = atkmods[2][sd->weapontype2];
+
+ // jobボーナス分
+ for(i=0;i<sd->status.job_level && i<MAX_LEVEL;i++){
+ if(job_bonus[s_class.upper][s_class.job][i])
+ sd->paramb[job_bonus[s_class.upper][s_class.job][i]-1]++;
+ }
+
+ if( (skill=pc_checkskill(sd,MC_INCCARRY))>0 ) // skill can be used with an item now, thanks to orn [Valaris]
+ sd->max_weight += skill*1000;
+
+ if( (skill=pc_checkskill(sd,AC_OWL))>0 ) // ふくろうの目
+ sd->paramb[4] += skill;
+
+ // ステータス変化による基本パラメータ補正
+ if(sd->sc_count){
+ if(sd->sc_data[SC_CONCENTRATE].timer!=-1 && sd->sc_data[SC_QUAGMIRE].timer == -1){ // 集中力向上
+ sd->paramb[1]+= (sd->status.agi+sd->paramb[1]+sd->parame[1]-sd->paramcard[1])*(2+sd->sc_data[SC_CONCENTRATE].val1)/100;
+ sd->paramb[4]+= (sd->status.dex+sd->paramb[4]+sd->parame[4]-sd->paramcard[4])*(2+sd->sc_data[SC_CONCENTRATE].val1)/100;
+ }
+ if(sd->sc_data[SC_INCREASEAGI].timer!=-1 && sd->sc_data[SC_QUAGMIRE].timer == -1 && sd->sc_data[SC_DONTFORGETME].timer == -1){ // 速度増加
+ sd->paramb[1]+= 2+sd->sc_data[SC_INCREASEAGI].val1;
+ sd->speed -= sd->speed *25/100;
+ }
+ if(sd->sc_data[SC_DECREASEAGI].timer!=-1) // 速度減少(agiはbattle.cで)
+ sd->speed = sd->speed *125/100;
+ if(sd->sc_data[SC_CLOAKING].timer!=-1)
+ sd->speed = (sd->speed*(76+(sd->sc_data[SC_INCREASEAGI].val1*3)))/100;
+ if(sd->sc_data[SC_CHASEWALK].timer!=-1)
+ sd->speed = sd->speed*(135-sd->sc_data[SC_CHASEWALK].val1*5)/100; // slow down by chasewalk
+ if(sd->sc_data[SC_BLESSING].timer!=-1){ // ブレッシング
+ sd->paramb[0]+= sd->sc_data[SC_BLESSING].val1;
+ sd->paramb[3]+= sd->sc_data[SC_BLESSING].val1;
+ sd->paramb[4]+= sd->sc_data[SC_BLESSING].val1;
+ }
+ if(sd->sc_data[SC_GLORIA].timer!=-1) // グロリア
+ sd->paramb[5]+= 30;
+ if(sd->sc_data[SC_LOUD].timer!=-1 && sd->sc_data[SC_QUAGMIRE].timer == -1) // ラウドボイス
+ sd->paramb[0]+= 4;
+ if(sd->sc_data[SC_QUAGMIRE].timer!=-1){ // クァグマイア
+ sd->speed = sd->speed*3/2;
+ sd->paramb[1]-=(sd->status.agi+sd->paramb[1]+sd->parame[1])/2;
+ sd->paramb[4]-=(sd->status.dex+sd->paramb[4]+sd->parame[4])/2;
+ }
+ if(sd->sc_data[SC_TRUESIGHT].timer!=-1){ // トゥルーサイト
+ sd->paramb[0]+= 5;
+ sd->paramb[1]+= 5;
+ sd->paramb[2]+= 5;
+ sd->paramb[3]+= 5;
+ sd->paramb[4]+= 5;
+ sd->paramb[5]+= 5;
+ }
+ }
+
+ //1度も死んでないJob70スパノビに+10
+ if(s_class.job == 23 && sd->die_counter == 0 && sd->status.job_level >= 70){
+ sd->paramb[0]+= 15;
+ sd->paramb[1]+= 15;
+ sd->paramb[2]+= 15;
+ sd->paramb[3]+= 15;
+ sd->paramb[4]+= 15;
+ sd->paramb[5]+= 15;
+ }
+ sd->paramc[0]=sd->status.str+sd->paramb[0]+sd->parame[0];
+ sd->paramc[1]=sd->status.agi+sd->paramb[1]+sd->parame[1];
+ sd->paramc[2]=sd->status.vit+sd->paramb[2]+sd->parame[2];
+ sd->paramc[3]=sd->status.int_+sd->paramb[3]+sd->parame[3];
+ sd->paramc[4]=sd->status.dex+sd->paramb[4]+sd->parame[4];
+ sd->paramc[5]=sd->status.luk+sd->paramb[5]+sd->parame[5];
+ for(i=0;i<6;i++)
+ if(sd->paramc[i] < 0) sd->paramc[i] = 0;
+
+ if(sd->status.weapon == 11 || sd->status.weapon == 13 || sd->status.weapon == 14) {
+ str = sd->paramc[4];
+ dex = sd->paramc[0];
+ }
+ else {
+ str = sd->paramc[0];
+ dex = sd->paramc[4];
+ }
+ dstr = str/10;
+ sd->base_atk += str + dstr*dstr + dex/5 + sd->paramc[5]/5;
+ sd->matk1 += sd->paramc[3]+(sd->paramc[3]/5)*(sd->paramc[3]/5);
+ sd->matk2 += sd->paramc[3]+(sd->paramc[3]/7)*(sd->paramc[3]/7);
+ if(sd->matk1 < sd->matk2) {
+ int temp = sd->matk2;
+ sd->matk2 = sd->matk1;
+ sd->matk1 = temp;
+ }
+ sd->hit += sd->paramc[4] + sd->status.base_level;
+ sd->flee += sd->paramc[1] + sd->status.base_level;
+ sd->def2 += sd->paramc[2];
+ sd->mdef2 += sd->paramc[3];
+ sd->flee2 += sd->paramc[5]+10;
+ sd->critical += (sd->paramc[5]*3)+10;
+
+ if(sd->base_atk < 1)
+ sd->base_atk = 1;
+ if(sd->critical_rate != 100)
+ sd->critical = (sd->critical*sd->critical_rate)/100;
+ if(sd->critical < 10) sd->critical = 10;
+ if(sd->hit_rate != 100)
+ sd->hit = (sd->hit*sd->hit_rate)/100;
+ if(sd->hit < 1) sd->hit = 1;
+ if(sd->flee_rate != 100)
+ sd->flee = (sd->flee*sd->flee_rate)/100;
+ if(sd->flee < 1) sd->flee = 1;
+ if(sd->flee2_rate != 100)
+ sd->flee2 = (sd->flee2*sd->flee2_rate)/100;
+ if(sd->flee2 < 10) sd->flee2 = 10;
+ if(sd->def_rate != 100)
+ sd->def = (sd->def*sd->def_rate)/100;
+ if(sd->def < 0) sd->def = 0;
+ if(sd->def2_rate != 100)
+ sd->def2 = (sd->def2*sd->def2_rate)/100;
+ if(sd->def2 < 1) sd->def2 = 1;
+ if(sd->mdef_rate != 100)
+ sd->mdef = (sd->mdef*sd->mdef_rate)/100;
+ if(sd->mdef < 0) sd->mdef = 0;
+ if(sd->mdef2_rate != 100)
+ sd->mdef2 = (sd->mdef2*sd->mdef2_rate)/100;
+ if(sd->mdef2 < 1) sd->mdef2 = 1;
+
+ // 二刀流 ASPD 修正
+ if (sd->status.weapon <= 16)
+ sd->aspd += aspd_base[s_class.job][sd->status.weapon]-(sd->paramc[1]*4+sd->paramc[4])*aspd_base[s_class.job][sd->status.weapon]/1000;
+ else
+ sd->aspd += (
+ (aspd_base[s_class.job][sd->weapontype1]-(sd->paramc[1]*4+sd->paramc[4])*aspd_base[s_class.job][sd->weapontype1]/1000) +
+ (aspd_base[s_class.job][sd->weapontype2]-(sd->paramc[1]*4+sd->paramc[4])*aspd_base[s_class.job][sd->weapontype2]/1000)
+ ) * 140 / 200;
+
+ aspd_rate = sd->aspd_rate;
+
+ //攻撃速度増加
+
+ if( (skill=pc_checkskill(sd,AC_VULTURE))>0){ // ワシの目
+ sd->hit += skill;
+ if(sd->status.weapon == 11)
+ sd->attackrange += skill;
+ }
+
+ if( (skill=pc_checkskill(sd,BS_WEAPONRESEARCH))>0) // 武器研究の命中率増加
+ sd->hit += skill*2;
+ if(sd->status.option&2 && (skill = pc_checkskill(sd,RG_TUNNELDRIVE))>0 ) // トンネルドライブ // トンネルドライブ
+ sd->speed += (1.2*DEFAULT_WALK_SPEED - skill*9);
+ if (pc_iscarton(sd) && (skill=pc_checkskill(sd,MC_PUSHCART))>0) // カートによる速度低下
+ sd->speed += (10-skill) * (DEFAULT_WALK_SPEED * 0.1);
+ else if (pc_isriding(sd)) // ペコペコ乗りによる速度増加
+ sd->speed -= (0.25 * DEFAULT_WALK_SPEED);
+ sd->max_weight += 1000;
+ if(sd->sc_count){
+ if(sd->sc_data[SC_WINDWALK].timer!=-1) //ウィンドウォーク時はLv*2%減算
+ sd->speed -= sd->speed *(sd->sc_data[SC_WINDWALK].val1*2)/100;
+ if(sd->sc_data[SC_CARTBOOST].timer!=-1) // カートブースト
+ sd->speed -= (DEFAULT_WALK_SPEED * 20)/100;
+ if(sd->sc_data[SC_BERSERK].timer!=-1) //バーサーク中はIAと同じぐらい速い?
+ sd->speed -= sd->speed *25/100;
+ if(sd->sc_data[SC_WEDDING].timer!=-1) //結婚中は歩くのが遅い
+ sd->speed = 2*DEFAULT_WALK_SPEED;
+ }
+
+ if((skill=pc_checkskill(sd,CR_TRUST))>0) { // フェイス
+ sd->status.max_hp += skill*200;
+ sd->subele[6] += skill*5;
+ }
+ if((skill=pc_checkskill(sd,BS_SKINTEMPER))>0)
+ sd->subele[3] += skill*4;
+
+ bl=sd->status.base_level;
+
+ sd->status.max_hp += (3500 + bl*hp_coefficient2[s_class.job] + hp_sigma_val[s_class.job][(bl > 0)? bl-1:0])/100 * (100 + sd->paramc[2])/100 + (sd->parame[2] - sd->paramcard[2]);
+ if (s_class.upper==1) // [MouseJstr]
+ sd->status.max_hp = sd->status.max_hp * 130/100;
+ if(sd->hprate!=100)
+ sd->status.max_hp = sd->status.max_hp*sd->hprate/100;
+
+ if(sd->sc_data && sd->sc_data[SC_BERSERK].timer!=-1){ // バーサーク
+ sd->status.max_hp = sd->status.max_hp * 3;
+ sd->status.hp = sd->status.hp * 3;
+ if(sd->status.max_hp > battle_config.max_hp) // removed negative max hp bug by Valaris
+ sd->status.max_hp = battle_config.max_hp;
+ if(sd->status.hp > battle_config.max_hp) // removed negative max hp bug by Valaris
+ sd->status.hp = battle_config.max_hp;
+ }
+ if(s_class.job == 23 && sd->status.base_level >= 99){
+ sd->status.max_hp = sd->status.max_hp + 2000;
+ }
+
+ if(sd->status.max_hp > battle_config.max_hp) // removed negative max hp bug by Valaris
+ sd->status.max_hp = battle_config.max_hp;
+ if(sd->status.max_hp <= 0) sd->status.max_hp = 1; // end
+
+ // 最大SP計算
+ sd->status.max_sp += ((sp_coefficient[s_class.job] * bl) + 1000)/100 * (100 + sd->paramc[3])/100 + (sd->parame[3] - sd->paramcard[3]);
+ if (s_class.upper==1) // [MouseJstr]
+ sd->status.max_sp = sd->status.max_sp * 130/100;
+ if(sd->sprate!=100)
+ sd->status.max_sp = sd->status.max_sp*sd->sprate/100;
+
+ if((skill=pc_checkskill(sd,HP_MEDITATIO))>0) // メディテイティオ
+ sd->status.max_sp += sd->status.max_sp*skill/100;
+ if((skill=pc_checkskill(sd,HW_SOULDRAIN))>0) /* ソウルドレイン */
+ sd->status.max_sp += sd->status.max_sp*2*skill/100;
+
+ if(sd->status.max_sp < 0 || sd->status.max_sp > battle_config.max_sp)
+ sd->status.max_sp = battle_config.max_sp;
+
+ //自然回復HP
+ sd->nhealhp = 1 + (sd->paramc[2]/5) + (sd->status.max_hp/200);
+ if((skill=pc_checkskill(sd,SM_RECOVERY)) > 0) { /* HP回復力向上 */
+ sd->nshealhp = skill*5 + (sd->status.max_hp*skill/500);
+ if(sd->nshealhp > 0x7fff) sd->nshealhp = 0x7fff;
+ }
+ //自然回復SP
+ sd->nhealsp = 1 + (sd->paramc[3]/6) + (sd->status.max_sp/100);
+ if(sd->paramc[3] >= 120)
+ sd->nhealsp += ((sd->paramc[3]-120)>>1) + 4;
+ if((skill=pc_checkskill(sd,MG_SRECOVERY)) > 0) { /* SP回復力向上 */
+ sd->nshealsp = skill*3 + (sd->status.max_sp*skill/500);
+ if(sd->nshealsp > 0x7fff) sd->nshealsp = 0x7fff;
+ }
+
+ if((skill = pc_checkskill(sd,MO_SPIRITSRECOVERY)) > 0) {
+ sd->nsshealhp = skill*4 + (sd->status.max_hp*skill/500);
+ sd->nsshealsp = skill*2 + (sd->status.max_sp*skill/500);
+ if(sd->nsshealhp > 0x7fff) sd->nsshealhp = 0x7fff;
+ if(sd->nsshealsp > 0x7fff) sd->nsshealsp = 0x7fff;
+ }
+ if(sd->hprecov_rate != 100) {
+ sd->nhealhp = sd->nhealhp*sd->hprecov_rate/100;
+ if(sd->nhealhp < 1) sd->nhealhp = 1;
+ }
+ if(sd->sprecov_rate != 100) {
+ sd->nhealsp = sd->nhealsp*sd->sprecov_rate/100;
+ if(sd->nhealsp < 1) sd->nhealsp = 1;
+ }
+ if((skill=pc_checkskill(sd,HP_MEDITATIO)) > 0) { // メディテイティオはSPRではなく自然回復にかかる
+ sd->nhealsp += 3*skill*(sd->status.max_sp)/100;
+ if(sd->nhealsp > 0x7fff) sd->nhealsp = 0x7fff;
+ }
+
+ // 種族耐性(これでいいの? ディバインプロテクションと同じ処理がいるかも)
+ if( (skill=pc_checkskill(sd,SA_DRAGONOLOGY))>0 ){ // ドラゴノロジー
+ skill = skill*4;
+ sd->addrace[9]+=skill;
+ sd->addrace_[9]+=skill;
+ sd->subrace[9]+=skill;
+ sd->magic_addrace[9]+=skill;
+ sd->magic_subrace[9]-=skill;
+ }
+
+ //Flee上昇
+ if( (skill=pc_checkskill(sd,TF_MISS))>0 ){ // 回避率増加
+ if(sd->status.class==6||sd->status.class==4007 || sd->status.class==23){
+ sd->flee += skill*3;
+ }
+ if(sd->status.class==12||sd->status.class==17||sd->status.class==4013||sd->status.class==4018)
+ sd->flee += skill*4;
+ if(sd->status.class==12||sd->status.class==4013)
+ sd->speed -= sd->speed *(skill*.5)/100;
+ }
+ if( (skill=pc_checkskill(sd,MO_DODGE))>0 ) // 見切り
+ sd->flee += (skill*3)>>1;
+
+ // スキルやステータス異常による残りのパラメータ補正
+ if(sd->sc_count){
+ // ATK/DEF変化形
+ if(sd->sc_data[SC_ANGELUS].timer!=-1) // エンジェラス
+ sd->def2 = sd->def2*(110+5*sd->sc_data[SC_ANGELUS].val1)/100;
+ if(sd->sc_data[SC_IMPOSITIO].timer!=-1) {// インポシティオマヌス
+ sd->watk += sd->sc_data[SC_IMPOSITIO].val1*5;
+ index = sd->equip_index[8];
+ if(index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == 4)
+ sd->watk_ += sd->sc_data[SC_IMPOSITIO].val1*5;
+ }
+ if(sd->sc_data[SC_PROVOKE].timer!=-1){ // プロボック
+ sd->def2 = sd->def2*(100-6*sd->sc_data[SC_PROVOKE].val1)/100;
+ sd->base_atk = sd->base_atk*(100+2*sd->sc_data[SC_PROVOKE].val1)/100;
+ sd->watk = sd->watk*(100+2*sd->sc_data[SC_PROVOKE].val1)/100;
+ index = sd->equip_index[8];
+ if(index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == 4)
+ sd->watk_ = sd->watk_*(100+2*sd->sc_data[SC_PROVOKE].val1)/100;
+ }
+ if(sd->sc_data[SC_ENDURE].timer!=-1)
+ sd->mdef2 += sd->sc_data[SC_ENDURE].val1;
+ if(sd->sc_data[SC_MINDBREAKER].timer!=-1){ // プロボック
+ sd->mdef2 = sd->mdef2*(100-6*sd->sc_data[SC_MINDBREAKER].val1)/100;
+ sd->matk1 = sd->matk1*(100+2*sd->sc_data[SC_MINDBREAKER].val1)/100;
+ sd->matk2 = sd->matk2*(100+2*sd->sc_data[SC_MINDBREAKER].val1)/100;
+ }
+ if(sd->sc_data[SC_POISON].timer!=-1) // 毒状態
+ sd->def2 = sd->def2*75/100;
+ if(sd->sc_data[SC_DRUMBATTLE].timer!=-1){ // 戦太鼓の響き
+ sd->watk += sd->sc_data[SC_DRUMBATTLE].val2;
+ sd->def += sd->sc_data[SC_DRUMBATTLE].val3;
+ index = sd->equip_index[8];
+ if(index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == 4)
+ sd->watk_ += sd->sc_data[SC_DRUMBATTLE].val2;
+ }
+ if(sd->sc_data[SC_NIBELUNGEN].timer!=-1) { // ニーベルングの指輪
+ index = sd->equip_index[9];
+ if(index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->wlv == 3)
+ sd->watk += sd->sc_data[SC_NIBELUNGEN].val3;
+ index = sd->equip_index[8];
+ if(index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->wlv == 3)
+ sd->watk_ += sd->sc_data[SC_NIBELUNGEN].val3;
+ if(index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->wlv == 4)
+ sd->watk += sd->sc_data[SC_NIBELUNGEN].val2;
+ index = sd->equip_index[8];
+ if(index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->wlv == 4)
+ sd->watk_ += sd->sc_data[SC_NIBELUNGEN].val2;
+ }
+
+ if(sd->sc_data[SC_VOLCANO].timer!=-1 && sd->def_ele==3){ // ボルケーノ
+ sd->watk += sd->sc_data[SC_VIOLENTGALE].val3;
+ }
+
+ if(sd->sc_data[SC_SIGNUMCRUCIS].timer!=-1)
+ sd->def = sd->def * (100 - sd->sc_data[SC_SIGNUMCRUCIS].val2)/100;
+ if(sd->sc_data[SC_ETERNALCHAOS].timer!=-1) // エターナルカオス
+ sd->def=0;
+
+ if(sd->sc_data[SC_CONCENTRATION].timer!=-1){ //コンセントレーション
+ sd->watk = sd->watk * (100 + 5*sd->sc_data[SC_CONCENTRATION].val1)/100;
+ index = sd->equip_index[8];
+ if(index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == 4)
+ sd->watk_ = sd->watk * (100 + 5*sd->sc_data[SC_CONCENTRATION].val1)/100;
+ sd->def = sd->def * (100 - 5*sd->sc_data[SC_CONCENTRATION].val1)/100;
+ }
+
+ if(sd->sc_data[SC_MAGICPOWER].timer!=-1){ //魔法力増幅
+ sd->matk1 = sd->matk1*(100+2*sd->sc_data[SC_MAGICPOWER].val1)/100;
+ sd->matk2 = sd->matk2*(100+2*sd->sc_data[SC_MAGICPOWER].val1)/100;
+ }
+ if(sd->sc_data[SC_ATKPOT].timer!=-1)
+ sd->watk += sd->sc_data[SC_ATKPOT].val1;
+ if(sd->sc_data[SC_MATKPOT].timer!=-1){
+ sd->matk1 += sd->sc_data[SC_MATKPOT].val1;
+ sd->matk2 += sd->sc_data[SC_MATKPOT].val1;
+ }
+
+ // ASPD/移動速度変化系
+ if(sd->sc_data[SC_TWOHANDQUICKEN].timer != -1 && sd->sc_data[SC_QUAGMIRE].timer == -1 && sd->sc_data[SC_DONTFORGETME].timer == -1) // 2HQ
+ aspd_rate -= 30;
+ if(sd->sc_data[SC_ADRENALINE].timer != -1 && sd->sc_data[SC_TWOHANDQUICKEN].timer == -1 &&
+ sd->sc_data[SC_QUAGMIRE].timer == -1 && sd->sc_data[SC_DONTFORGETME].timer == -1) { // アドレナリンラッシュ
+ if(sd->sc_data[SC_ADRENALINE].val2 || !battle_config.party_skill_penaly)
+ aspd_rate -= 30;
+ else
+ aspd_rate -= 25;
+ }
+ if(sd->sc_data[SC_SPEARSQUICKEN].timer != -1 && sd->sc_data[SC_ADRENALINE].timer == -1 &&
+ sd->sc_data[SC_TWOHANDQUICKEN].timer == -1 && sd->sc_data[SC_QUAGMIRE].timer == -1 && sd->sc_data[SC_DONTFORGETME].timer == -1) // スピアクィッケン
+ aspd_rate -= sd->sc_data[SC_SPEARSQUICKEN].val2;
+ if(sd->sc_data[SC_ASSNCROS].timer!=-1 && // 夕陽のアサシンクロス
+ sd->sc_data[SC_TWOHANDQUICKEN].timer==-1 && sd->sc_data[SC_ADRENALINE].timer==-1 && sd->sc_data[SC_SPEARSQUICKEN].timer==-1 &&
+ sd->sc_data[SC_DONTFORGETME].timer == -1)
+ aspd_rate -= 5+sd->sc_data[SC_ASSNCROS].val1+sd->sc_data[SC_ASSNCROS].val2+sd->sc_data[SC_ASSNCROS].val3;
+ if(sd->sc_data[SC_DONTFORGETME].timer!=-1){ // 私を忘れないで
+ aspd_rate += sd->sc_data[SC_DONTFORGETME].val1*3 + sd->sc_data[SC_DONTFORGETME].val2 + (sd->sc_data[SC_DONTFORGETME].val3>>16);
+ sd->speed= sd->speed*(100+sd->sc_data[SC_DONTFORGETME].val1*2 + sd->sc_data[SC_DONTFORGETME].val2 + (sd->sc_data[SC_DONTFORGETME].val3&0xffff))/100;
+ }
+ if( sd->sc_data[i=SC_SPEEDPOTION2].timer!=-1 ||
+ sd->sc_data[i=SC_SPEEDPOTION1].timer!=-1 ||
+ sd->sc_data[i=SC_SPEEDPOTION0].timer!=-1) // 増 速ポーション
+ aspd_rate -= sd->sc_data[i].val2;
+
+ // HIT/FLEE変化系
+ if(sd->sc_data[SC_WHISTLE].timer!=-1){ // 口笛
+ sd->flee += sd->flee * (sd->sc_data[SC_WHISTLE].val1
+ +sd->sc_data[SC_WHISTLE].val2+(sd->sc_data[SC_WHISTLE].val3>>16))/100;
+ sd->flee2+= (sd->sc_data[SC_WHISTLE].val1+sd->sc_data[SC_WHISTLE].val2+(sd->sc_data[SC_WHISTLE].val3&0xffff)) * 10;
+ }
+ if(sd->sc_data[SC_HUMMING].timer!=-1) // ハミング
+ sd->hit += (sd->sc_data[SC_HUMMING].val1*2+sd->sc_data[SC_HUMMING].val2
+ +sd->sc_data[SC_HUMMING].val3) * sd->hit/100;
+ if(sd->sc_data[SC_VIOLENTGALE].timer!=-1 && sd->def_ele==4){ // バイオレントゲイル
+ sd->flee += sd->flee*sd->sc_data[SC_VIOLENTGALE].val3/100;
+ }
+ if(sd->sc_data[SC_BLIND].timer!=-1){ // 暗黒
+ sd->hit -= sd->hit*25/100;
+ sd->flee -= sd->flee*25/100;
+ }
+ if(sd->sc_data[SC_WINDWALK].timer!=-1) // ウィンドウォーク
+ sd->flee += sd->flee*(sd->sc_data[SC_WINDWALK].val2)/100;
+ if(sd->sc_data[SC_SPIDERWEB].timer!=-1) //スパイダーウェブ
+ sd->flee -= sd->flee*50/100;
+ if(sd->sc_data[SC_TRUESIGHT].timer!=-1) //トゥルーサイト
+ sd->hit += 3*(sd->sc_data[SC_TRUESIGHT].val1);
+ if(sd->sc_data[SC_CONCENTRATION].timer!=-1) //コンセントレーション
+ sd->hit += (10*(sd->sc_data[SC_CONCENTRATION].val1));
+
+ // 耐性
+ if(sd->sc_data[SC_SIEGFRIED].timer!=-1){ // 不死身のジークフリード
+ sd->subele[1] += sd->sc_data[SC_SIEGFRIED].val2; // 水
+ sd->subele[2] += sd->sc_data[SC_SIEGFRIED].val2; // 水
+ sd->subele[3] += sd->sc_data[SC_SIEGFRIED].val2; // 火
+ sd->subele[4] += sd->sc_data[SC_SIEGFRIED].val2; // 水
+ sd->subele[5] += sd->sc_data[SC_SIEGFRIED].val2; // 水
+ sd->subele[6] += sd->sc_data[SC_SIEGFRIED].val2; // 水
+ sd->subele[7] += sd->sc_data[SC_SIEGFRIED].val2; // 水
+ sd->subele[8] += sd->sc_data[SC_SIEGFRIED].val2; // 水
+ sd->subele[9] += sd->sc_data[SC_SIEGFRIED].val2; // 水
+ }
+ if(sd->sc_data[SC_PROVIDENCE].timer!=-1){ // プロヴィデンス
+ sd->subele[6] += sd->sc_data[SC_PROVIDENCE].val2; // 対 聖属性
+ sd->subrace[6] += sd->sc_data[SC_PROVIDENCE].val2; // 対 悪魔
+ }
+
+ // その他
+ if(sd->sc_data[SC_APPLEIDUN].timer!=-1){ // イドゥンの林檎
+ sd->status.max_hp += ((5+sd->sc_data[SC_APPLEIDUN].val1*2+((sd->sc_data[SC_APPLEIDUN].val2+1)>>1)
+ +sd->sc_data[SC_APPLEIDUN].val3/10) * sd->status.max_hp)/100;
+ if(sd->status.max_hp < 0 || sd->status.max_hp > battle_config.max_hp)
+ sd->status.max_hp = battle_config.max_hp;
+ }
+ if(sd->sc_data[SC_DELUGE].timer!=-1 && sd->def_ele==1){ // デリュージ
+ sd->status.max_hp += sd->status.max_hp*sd->sc_data[SC_DELUGE].val3/100;
+ if(sd->status.max_hp < 0 || sd->status.max_hp > battle_config.max_hp)
+ sd->status.max_hp = battle_config.max_hp;
+ }
+ if(sd->sc_data[SC_SERVICE4U].timer!=-1) { // サービスフォーユー
+ sd->status.max_sp += sd->status.max_sp*(10+sd->sc_data[SC_SERVICE4U].val1+sd->sc_data[SC_SERVICE4U].val2
+ +sd->sc_data[SC_SERVICE4U].val3)/100;
+ if(sd->status.max_sp < 0 || sd->status.max_sp > battle_config.max_sp)
+ sd->status.max_sp = battle_config.max_sp;
+ sd->dsprate-=(10+sd->sc_data[SC_SERVICE4U].val1*3+sd->sc_data[SC_SERVICE4U].val2
+ +sd->sc_data[SC_SERVICE4U].val3);
+ if(sd->dsprate<0)sd->dsprate=0;
+ }
+
+ if(sd->sc_data[SC_FORTUNE].timer!=-1) // 幸運のキス
+ sd->critical += (10+sd->sc_data[SC_FORTUNE].val1+sd->sc_data[SC_FORTUNE].val2
+ +sd->sc_data[SC_FORTUNE].val3)*10;
+
+ if(sd->sc_data[SC_EXPLOSIONSPIRITS].timer!=-1){ // 爆裂波動
+ if(s_class.job==23)
+ sd->critical += sd->sc_data[SC_EXPLOSIONSPIRITS].val1*100;
+ else
+ sd->critical += sd->sc_data[SC_EXPLOSIONSPIRITS].val2;
+ }
+
+ if(sd->sc_data[SC_STEELBODY].timer!=-1){ // 金剛
+ sd->def = 90;
+ sd->mdef = 90;
+ aspd_rate += 25;
+ sd->speed = (sd->speed * 125) / 100;
+ }
+ if(sd->sc_data[SC_DEFENDER].timer != -1) {
+ sd->aspd += (550 - sd->sc_data[SC_DEFENDER].val1*50);
+ sd->speed = (sd->speed * (155 - sd->sc_data[SC_DEFENDER].val1*5)) / 100;
+ }
+ if(sd->sc_data[SC_ENCPOISON].timer != -1)
+ sd->addeff[4] += sd->sc_data[SC_ENCPOISON].val2;
+
+ if( sd->sc_data[SC_DANCING].timer!=-1 ){ // 演奏/ダンス使用中
+ sd->speed*=4;
+ sd->nhealsp = 0;
+ sd->nshealsp = 0;
+ sd->nsshealsp = 0;
+ }
+ if(sd->sc_data[SC_CURSE].timer!=-1)
+ sd->speed += 450;
+
+ if(sd->sc_data[SC_TRUESIGHT].timer!=-1) //トゥルーサイト
+ sd->critical += sd->critical*(sd->sc_data[SC_TRUESIGHT].val1)/100;
+
+/* if(sd->sc_data[SC_VOLCANO].timer!=-1) // エンチャントポイズン(属性はbattle.cで)
+ sd->addeff[2]+=sd->sc_data[SC_VOLCANO].val2;//% of granting
+ if(sd->sc_data[SC_DELUGE].timer!=-1) // エンチャントポイズン(属性はbattle.cで)
+ sd->addeff[0]+=sd->sc_data[SC_DELUGE].val2;//% of granting
+ */
+ }
+
+ if(sd->speed_rate != 100)
+ sd->speed = sd->speed*sd->speed_rate/100;
+ if(sd->speed < 1) sd->speed = 1;
+ if(aspd_rate != 100)
+ sd->aspd = sd->aspd*aspd_rate/100;
+ if(pc_isriding(sd)) // 騎兵修練
+ sd->aspd = sd->aspd*(100 + 10*(5 - pc_checkskill(sd,KN_CAVALIERMASTERY)))/ 100;
+ if(sd->aspd < battle_config.max_aspd) sd->aspd = battle_config.max_aspd;
+ sd->amotion = sd->aspd;
+ sd->dmotion = 800-sd->paramc[1]*4;
+ if(sd->dmotion<400)
+ sd->dmotion = 400;
+ if(sd->skilltimer != -1 && (skill = pc_checkskill(sd,SA_FREECAST)) > 0) {
+ sd->prev_speed = sd->speed;
+ sd->speed = sd->speed*(175 - skill*5)/100;
+ }
+
+ if(sd->status.hp>sd->status.max_hp)
+ sd->status.hp=sd->status.max_hp;
+ if(sd->status.sp>sd->status.max_sp)
+ sd->status.sp=sd->status.max_sp;
+
+ if(first&4)
+ return 0;
+ if(first&3) {
+ clif_updatestatus(sd,SP_SPEED);
+ clif_updatestatus(sd,SP_MAXHP);
+ clif_updatestatus(sd,SP_MAXSP);
+ if(first&1) {
+ clif_updatestatus(sd,SP_HP);
+ clif_updatestatus(sd,SP_SP);
+ }
+ return 0;
+ }
+
+ if(b_class != sd->view_class) {
+ clif_changelook(&sd->bl,LOOK_BASE,sd->view_class);
+#if PACKETVER < 4
+ clif_changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon);
+ clif_changelook(&sd->bl,LOOK_SHIELD,sd->status.shield);
+#else
+ clif_changelook(&sd->bl,LOOK_WEAPON,0);
+#endif
+ }
+
+ if( memcmp(b_skill,sd->status.skill,sizeof(sd->status.skill)) || b_attackrange != sd->attackrange)
+ clif_skillinfoblock(sd); // スキル送信
+
+ if(b_speed != sd->speed)
+ clif_updatestatus(sd,SP_SPEED);
+ if(b_weight != sd->weight)
+ clif_updatestatus(sd,SP_WEIGHT);
+ if(b_max_weight != sd->max_weight) {
+ clif_updatestatus(sd,SP_MAXWEIGHT);
+ pc_checkweighticon(sd);
+ }
+ for(i=0;i<6;i++)
+ if(b_paramb[i] + b_parame[i] != sd->paramb[i] + sd->parame[i])
+ clif_updatestatus(sd,SP_STR+i);
+ if(b_hit != sd->hit)
+ clif_updatestatus(sd,SP_HIT);
+ if(b_flee != sd->flee)
+ clif_updatestatus(sd,SP_FLEE1);
+ if(b_aspd != sd->aspd)
+ clif_updatestatus(sd,SP_ASPD);
+ if(b_watk != sd->watk || b_base_atk != sd->base_atk)
+ clif_updatestatus(sd,SP_ATK1);
+ if(b_def != sd->def)
+ clif_updatestatus(sd,SP_DEF1);
+ if(b_watk2 != sd->watk2)
+ clif_updatestatus(sd,SP_ATK2);
+ if(b_def2 != sd->def2)
+ clif_updatestatus(sd,SP_DEF2);
+ if(b_flee2 != sd->flee2)
+ clif_updatestatus(sd,SP_FLEE2);
+ if(b_critical != sd->critical)
+ clif_updatestatus(sd,SP_CRITICAL);
+ if(b_matk1 != sd->matk1)
+ clif_updatestatus(sd,SP_MATK1);
+ if(b_matk2 != sd->matk2)
+ clif_updatestatus(sd,SP_MATK2);
+ if(b_mdef != sd->mdef)
+ clif_updatestatus(sd,SP_MDEF1);
+ if(b_mdef2 != sd->mdef2)
+ clif_updatestatus(sd,SP_MDEF2);
+ if(b_attackrange != sd->attackrange)
+ clif_updatestatus(sd,SP_ATTACKRANGE);
+ if(b_max_hp != sd->status.max_hp)
+ clif_updatestatus(sd,SP_MAXHP);
+ if(b_max_sp != sd->status.max_sp)
+ clif_updatestatus(sd,SP_MAXSP);
+ if(b_hp != sd->status.hp)
+ clif_updatestatus(sd,SP_HP);
+ if(b_sp != sd->status.sp)
+ clif_updatestatus(sd,SP_SP);
+
+/* if(before.cart_num != before.cart_num || before.cart_max_num != before.cart_max_num ||
+ before.cart_weight != before.cart_weight || before.cart_max_weight != before.cart_max_weight )
+ clif_updatestatus(sd,SP_CARTINFO);*/
+
+ if(sd->status.hp<sd->status.max_hp>>2 && pc_checkskill(sd,SM_AUTOBERSERK)>0 &&
+ (sd->sc_data[SC_PROVOKE].timer==-1 || sd->sc_data[SC_PROVOKE].val2==0 ) && !pc_isdead(sd))
+ // オートバーサーク発動
+ skill_status_change_start(&sd->bl,SC_PROVOKE,10,1,0,0,0,0);
+
+ return 0;
+}
+
+/*==========================================
+ * 装 備品による能力等のボーナス設定
+ *------------------------------------------
+ */
+int pc_bonus(struct map_session_data *sd,int type,int val)
+{
+ nullpo_retr(0, sd);
+
+ switch(type){
+ case SP_STR:
+ case SP_AGI:
+ case SP_VIT:
+ case SP_INT:
+ case SP_DEX:
+ case SP_LUK:
+ if(sd->state.lr_flag != 2)
+ sd->parame[type-SP_STR]+=val;
+ break;
+ case SP_ATK1:
+ if(!sd->state.lr_flag)
+ sd->watk+=val;
+ else if(sd->state.lr_flag == 1)
+ sd->watk_+=val;
+ break;
+ case SP_ATK2:
+ if(!sd->state.lr_flag)
+ sd->watk2+=val;
+ else if(sd->state.lr_flag == 1)
+ sd->watk_2+=val;
+ break;
+ case SP_BASE_ATK:
+ if(sd->state.lr_flag != 2)
+ sd->base_atk+=val;
+ break;
+ case SP_MATK1:
+ if(sd->state.lr_flag != 2)
+ sd->matk1 += val;
+ break;
+ case SP_MATK2:
+ if(sd->state.lr_flag != 2)
+ sd->matk2 += val;
+ break;
+ case SP_MATK:
+ if(sd->state.lr_flag != 2) {
+ sd->matk1 += val;
+ sd->matk2 += val;
+ }
+ break;
+ case SP_DEF1:
+ if(sd->state.lr_flag != 2)
+ sd->def+=val;
+ break;
+ case SP_MDEF1:
+ if(sd->state.lr_flag != 2)
+ sd->mdef+=val;
+ break;
+ case SP_MDEF2:
+ if(sd->state.lr_flag != 2)
+ sd->mdef+=val;
+ break;
+ case SP_HIT:
+ if(sd->state.lr_flag != 2)
+ sd->hit+=val;
+ else
+ sd->arrow_hit+=val;
+ break;
+ case SP_FLEE1:
+ if(sd->state.lr_flag != 2)
+ sd->flee+=val;
+ break;
+ case SP_FLEE2:
+ if(sd->state.lr_flag != 2)
+ sd->flee2+=val*10;
+ break;
+ case SP_CRITICAL:
+ if(sd->state.lr_flag != 2)
+ sd->critical+=val*10;
+ else
+ sd->arrow_cri += val*10;
+ break;
+ case SP_ATKELE:
+ if(!sd->state.lr_flag)
+ sd->atk_ele=val;
+ else if(sd->state.lr_flag == 1)
+ sd->atk_ele_=val;
+ else if(sd->state.lr_flag == 2)
+ sd->arrow_ele=val;
+ break;
+ case SP_DEFELE:
+ if(sd->state.lr_flag != 2)
+ sd->def_ele=val;
+ break;
+ case SP_MAXHP:
+ if(sd->state.lr_flag != 2)
+ sd->status.max_hp+=val;
+ break;
+ case SP_MAXSP:
+ if(sd->state.lr_flag != 2)
+ sd->status.max_sp+=val;
+ break;
+ case SP_CASTRATE:
+ if(sd->state.lr_flag != 2)
+ sd->castrate+=val;
+ break;
+ case SP_MAXHPRATE:
+ if(sd->state.lr_flag != 2)
+ sd->hprate+=val;
+ break;
+ case SP_MAXSPRATE:
+ if(sd->state.lr_flag != 2)
+ sd->sprate+=val;
+ break;
+ case SP_SPRATE:
+ if(sd->state.lr_flag != 2)
+ sd->dsprate+=val;
+ break;
+ case SP_ATTACKRANGE:
+ if(!sd->state.lr_flag)
+ sd->attackrange += val;
+ else if(sd->state.lr_flag == 1)
+ sd->attackrange_ += val;
+ else if(sd->state.lr_flag == 2)
+ sd->arrow_range += val;
+ break;
+ case SP_ADD_SPEED:
+ if(sd->state.lr_flag != 2)
+ sd->speed -= val;
+ break;
+ case SP_SPEED_RATE:
+ if(sd->state.lr_flag != 2) {
+ if(sd->speed_rate > 100-val)
+ sd->speed_rate = 100-val;
+ }
+ break;
+ case SP_SPEED_ADDRATE:
+ if(sd->state.lr_flag != 2)
+ sd->speed_add_rate = sd->speed_add_rate * (100-val)/100;
+ break;
+ case SP_ASPD:
+ if(sd->state.lr_flag != 2)
+ sd->aspd -= val*10;
+ break;
+ case SP_ASPD_RATE:
+ if(sd->state.lr_flag != 2) {
+ if(sd->aspd_rate > 100-val)
+ sd->aspd_rate = 100-val;
+ }
+ break;
+ case SP_ASPD_ADDRATE:
+ if(sd->state.lr_flag != 2)
+ sd->aspd_add_rate = sd->aspd_add_rate * (100-val)/100;
+ break;
+ case SP_HP_RECOV_RATE:
+ if(sd->state.lr_flag != 2)
+ sd->hprecov_rate += val;
+ break;
+ case SP_SP_RECOV_RATE:
+ if(sd->state.lr_flag != 2)
+ sd->sprecov_rate += val;
+ break;
+ case SP_CRITICAL_DEF:
+ if(sd->state.lr_flag != 2)
+ sd->critical_def += val;
+ break;
+ case SP_NEAR_ATK_DEF:
+ if(sd->state.lr_flag != 2)
+ sd->near_attack_def_rate += val;
+ break;
+ case SP_LONG_ATK_DEF:
+ if(sd->state.lr_flag != 2)
+ sd->long_attack_def_rate += val;
+ break;
+ case SP_DOUBLE_RATE:
+ if(sd->state.lr_flag == 0 && sd->double_rate < val)
+ sd->double_rate = val;
+ break;
+ case SP_DOUBLE_ADD_RATE:
+ if(sd->state.lr_flag == 0)
+ sd->double_add_rate += val;
+ break;
+ case SP_MATK_RATE:
+ if(sd->state.lr_flag != 2)
+ sd->matk_rate += val;
+ break;
+ case SP_IGNORE_DEF_ELE:
+ if(!sd->state.lr_flag)
+ sd->ignore_def_ele |= 1<<val;
+ else if(sd->state.lr_flag == 1)
+ sd->ignore_def_ele_ |= 1<<val;
+ break;
+ case SP_IGNORE_DEF_RACE:
+ if(!sd->state.lr_flag)
+ sd->ignore_def_race |= 1<<val;
+ else if(sd->state.lr_flag == 1)
+ sd->ignore_def_race_ |= 1<<val;
+ break;
+ case SP_ATK_RATE:
+ if(sd->state.lr_flag != 2)
+ sd->atk_rate += val;
+ break;
+ case SP_MAGIC_ATK_DEF:
+ if(sd->state.lr_flag != 2)
+ sd->magic_def_rate += val;
+ break;
+ case SP_MISC_ATK_DEF:
+ if(sd->state.lr_flag != 2)
+ sd->misc_def_rate += val;
+ break;
+ case SP_IGNORE_MDEF_ELE:
+ if(sd->state.lr_flag != 2)
+ sd->ignore_mdef_ele |= 1<<val;
+ break;
+ case SP_IGNORE_MDEF_RACE:
+ if(sd->state.lr_flag != 2)
+ sd->ignore_mdef_race |= 1<<val;
+ break;
+ case SP_PERFECT_HIT_RATE:
+ if(sd->state.lr_flag != 2 && sd->perfect_hit < val)
+ sd->perfect_hit = val;
+ break;
+ case SP_PERFECT_HIT_ADD_RATE:
+ if(sd->state.lr_flag != 2)
+ sd->perfect_hit_add += val;
+ break;
+ case SP_CRITICAL_RATE:
+ if(sd->state.lr_flag != 2)
+ sd->critical_rate+=val;
+ break;
+ case SP_GET_ZENY_NUM:
+ if(sd->state.lr_flag != 2 && sd->get_zeny_num < val)
+ sd->get_zeny_num = val;
+ break;
+ case SP_ADD_GET_ZENY_NUM:
+ if(sd->state.lr_flag != 2)
+ sd->get_zeny_add_num += val;
+ break;
+ case SP_DEF_RATIO_ATK_ELE:
+ if(!sd->state.lr_flag)
+ sd->def_ratio_atk_ele |= 1<<val;
+ else if(sd->state.lr_flag == 1)
+ sd->def_ratio_atk_ele_ |= 1<<val;
+ break;
+ case SP_DEF_RATIO_ATK_RACE:
+ if(!sd->state.lr_flag)
+ sd->def_ratio_atk_race |= 1<<val;
+ else if(sd->state.lr_flag == 1)
+ sd->def_ratio_atk_race_ |= 1<<val;
+ break;
+ case SP_HIT_RATE:
+ if(sd->state.lr_flag != 2)
+ sd->hit_rate += val;
+ break;
+ case SP_FLEE_RATE:
+ if(sd->state.lr_flag != 2)
+ sd->flee_rate += val;
+ break;
+ case SP_FLEE2_RATE:
+ if(sd->state.lr_flag != 2)
+ sd->flee2_rate += val;
+ break;
+ case SP_DEF_RATE:
+ if(sd->state.lr_flag != 2)
+ sd->def_rate += val;
+ break;
+ case SP_DEF2_RATE:
+ if(sd->state.lr_flag != 2)
+ sd->def2_rate += val;
+ break;
+ case SP_MDEF_RATE:
+ if(sd->state.lr_flag != 2)
+ sd->mdef_rate += val;
+ break;
+ case SP_MDEF2_RATE:
+ if(sd->state.lr_flag != 2)
+ sd->mdef2_rate += val;
+ break;
+ case SP_RESTART_FULL_RECORVER:
+ if(sd->state.lr_flag != 2)
+ sd->special_state.restart_full_recover = 1;
+ break;
+ case SP_NO_CASTCANCEL:
+ if(sd->state.lr_flag != 2)
+ sd->special_state.no_castcancel = 1;
+ break;
+ case SP_NO_CASTCANCEL2:
+ if(sd->state.lr_flag != 2)
+ sd->special_state.no_castcancel2 = 1;
+ break;
+ case SP_NO_SIZEFIX:
+ if(sd->state.lr_flag != 2)
+ sd->special_state.no_sizefix = 1;
+ break;
+ case SP_NO_MAGIC_DAMAGE:
+ if(sd->state.lr_flag != 2)
+ sd->special_state.no_magic_damage = 1;
+ break;
+ case SP_NO_WEAPON_DAMAGE:
+ if(sd->state.lr_flag != 2)
+ sd->special_state.no_weapon_damage = 1;
+ break;
+ case SP_NO_GEMSTONE:
+ if(sd->state.lr_flag != 2)
+ sd->special_state.no_gemstone = 1;
+ break;
+ case SP_INFINITE_ENDURE:
+ if(sd->state.lr_flag != 2)
+ sd->special_state.infinite_endure = 1;
+ break;
+ case SP_SPLASH_RANGE:
+ if(sd->state.lr_flag != 2 && sd->splash_range < val)
+ sd->splash_range = val;
+ break;
+ case SP_SPLASH_ADD_RANGE:
+ if(sd->state.lr_flag != 2)
+ sd->splash_add_range += val;
+ break;
+ case SP_SHORT_WEAPON_DAMAGE_RETURN:
+ if(sd->state.lr_flag != 2)
+ sd->short_weapon_damage_return += val;
+ break;
+ case SP_LONG_WEAPON_DAMAGE_RETURN:
+ if(sd->state.lr_flag != 2)
+ sd->long_weapon_damage_return += val;
+ break;
+ case SP_MAGIC_DAMAGE_RETURN: //AppleGirl Was Here
+ if(sd->state.lr_flag != 2)
+ sd->magic_damage_return += val;
+ break;
+ case SP_ALL_STATS: // [Valaris]
+ if(sd->state.lr_flag!=2) {
+ sd->parame[SP_STR-SP_STR]+=val;
+ sd->parame[SP_AGI-SP_STR]+=val;
+ sd->parame[SP_VIT-SP_STR]+=val;
+ sd->parame[SP_INT-SP_STR]+=val;
+ sd->parame[SP_DEX-SP_STR]+=val;
+ sd->parame[SP_LUK-SP_STR]+=val;
+ clif_updatestatus(sd,13);
+ clif_updatestatus(sd,14);
+ clif_updatestatus(sd,15);
+ clif_updatestatus(sd,16);
+ clif_updatestatus(sd,17);
+ clif_updatestatus(sd,18);
+ }
+ break;
+ case SP_AGI_VIT: // [Valaris]
+ if(sd->state.lr_flag!=2) {
+ sd->parame[SP_AGI-SP_STR]+=val;
+ sd->parame[SP_VIT-SP_STR]+=val;
+ clif_updatestatus(sd,14);
+ clif_updatestatus(sd,15);
+ }
+ break;
+ case SP_AGI_DEX_STR: // [Valaris]
+ if(sd->state.lr_flag!=2) {
+ sd->parame[SP_AGI-SP_STR]+=val;
+ sd->parame[SP_DEX-SP_STR]+=val;
+ sd->parame[SP_STR-SP_STR]+=val;
+ clif_updatestatus(sd,14);
+ clif_updatestatus(sd,17);
+ clif_updatestatus(sd,13);
+ }
+ break;
+ case SP_PERFECT_HIDE: // [Valaris]
+ if(sd->state.lr_flag!=2) {
+ sd->perfect_hiding=1;
+ }
+ break;
+ case SP_DISGUISE: // Disguise script for items [Valaris]
+ if(sd->state.lr_flag!=2 && sd->disguiseflag==0) {
+ if(pc_isriding(sd)) { // temporary prevention of crash caused by peco + disguise, will look into a better solution [Valaris]
+ clif_displaymessage(sd->fd, "Cannot wear disguise when riding a Peco.");
+ break;
+ }
+ sd->disguise=val;
+ clif_clearchar(&sd->bl, 9);
+ pc_setpos(sd, sd->mapname, sd->bl.x, sd->bl.y, 3);
+ }
+ break;
+ case SP_UNBREAKABLE:
+ if(sd->state.lr_flag!=2) {
+ sd->unbreakable += val;
+ }
+ break;
+ default:
+ if(battle_config.error_log)
+ printf("pc_bonus: unknown type %d %d !\n",type,val);
+ break;
+ }
+ return 0;
+}
+
+/*==========================================
+ * 装 備品による能力等のボーナス設定
+ *------------------------------------------
+ */
+int pc_bonus2(struct map_session_data *sd,int type,int type2,int val)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ switch(type){
+ case SP_ADDELE:
+ if(!sd->state.lr_flag)
+ sd->addele[type2]+=val;
+ else if(sd->state.lr_flag == 1)
+ sd->addele_[type2]+=val;
+ else if(sd->state.lr_flag == 2)
+ sd->arrow_addele[type2]+=val;
+ break;
+ case SP_ADDRACE:
+ if(!sd->state.lr_flag)
+ sd->addrace[type2]+=val;
+ else if(sd->state.lr_flag == 1)
+ sd->addrace_[type2]+=val;
+ else if(sd->state.lr_flag == 2)
+ sd->arrow_addrace[type2]+=val;
+ break;
+ case SP_ADDSIZE:
+ if(!sd->state.lr_flag)
+ sd->addsize[type2]+=val;
+ else if(sd->state.lr_flag == 1)
+ sd->addsize_[type2]+=val;
+ else if(sd->state.lr_flag == 2)
+ sd->arrow_addsize[type2]+=val;
+ break;
+ case SP_SUBELE:
+ if(sd->state.lr_flag != 2)
+ sd->subele[type2]+=val;
+ break;
+ case SP_SUBRACE:
+ if(sd->state.lr_flag != 2)
+ sd->subrace[type2]+=val;
+ break;
+ case SP_ADDEFF:
+ if(sd->state.lr_flag != 2)
+ sd->addeff[type2]+=val;
+ else
+ sd->arrow_addeff[type2]+=val;
+ break;
+ case SP_ADDEFF2:
+ if(sd->state.lr_flag != 2)
+ sd->addeff2[type2]+=val;
+ else
+ sd->arrow_addeff2[type2]+=val;
+ break;
+ case SP_RESEFF:
+ if(sd->state.lr_flag != 2)
+ sd->reseff[type2]+=val;
+ break;
+ case SP_MAGIC_ADDELE:
+ if(sd->state.lr_flag != 2)
+ sd->magic_addele[type2]+=val;
+ break;
+ case SP_MAGIC_ADDRACE:
+ if(sd->state.lr_flag != 2)
+ sd->magic_addrace[type2]+=val;
+ break;
+ case SP_MAGIC_SUBRACE:
+ if(sd->state.lr_flag != 2)
+ sd->magic_subrace[type2]+=val;
+ break;
+ case SP_ADD_DAMAGE_CLASS:
+ if(!sd->state.lr_flag) {
+ for(i=0;i<sd->add_damage_class_count;i++) {
+ if(sd->add_damage_classid[i] == type2) {
+ sd->add_damage_classrate[i] += val;
+ break;
+ }
+ }
+ if(i >= sd->add_damage_class_count && sd->add_damage_class_count < 10) {
+ sd->add_damage_classid[sd->add_damage_class_count] = type2;
+ sd->add_damage_classrate[sd->add_damage_class_count] += val;
+ sd->add_damage_class_count++;
+ }
+ }
+ else if(sd->state.lr_flag == 1) {
+ for(i=0;i<sd->add_damage_class_count_;i++) {
+ if(sd->add_damage_classid_[i] == type2) {
+ sd->add_damage_classrate_[i] += val;
+ break;
+ }
+ }
+ if(i >= sd->add_damage_class_count_ && sd->add_damage_class_count_ < 10) {
+ sd->add_damage_classid_[sd->add_damage_class_count_] = type2;
+ sd->add_damage_classrate_[sd->add_damage_class_count_] += val;
+ sd->add_damage_class_count_++;
+ }
+ }
+ break;
+ case SP_ADD_MAGIC_DAMAGE_CLASS:
+ if(sd->state.lr_flag != 2) {
+ for(i=0;i<sd->add_magic_damage_class_count;i++) {
+ if(sd->add_magic_damage_classid[i] == type2) {
+ sd->add_magic_damage_classrate[i] += val;
+ break;
+ }
+ }
+ if(i >= sd->add_magic_damage_class_count && sd->add_magic_damage_class_count < 10) {
+ sd->add_magic_damage_classid[sd->add_magic_damage_class_count] = type2;
+ sd->add_magic_damage_classrate[sd->add_magic_damage_class_count] += val;
+ sd->add_magic_damage_class_count++;
+ }
+ }
+ break;
+ case SP_ADD_DEF_CLASS:
+ if(sd->state.lr_flag != 2) {
+ for(i=0;i<sd->add_def_class_count;i++) {
+ if(sd->add_def_classid[i] == type2) {
+ sd->add_def_classrate[i] += val;
+ break;
+ }
+ }
+ if(i >= sd->add_def_class_count && sd->add_def_class_count < 10) {
+ sd->add_def_classid[sd->add_def_class_count] = type2;
+ sd->add_def_classrate[sd->add_def_class_count] += val;
+ sd->add_def_class_count++;
+ }
+ }
+ break;
+ case SP_ADD_MDEF_CLASS:
+ if(sd->state.lr_flag != 2) {
+ for(i=0;i<sd->add_mdef_class_count;i++) {
+ if(sd->add_mdef_classid[i] == type2) {
+ sd->add_mdef_classrate[i] += val;
+ break;
+ }
+ }
+ if(i >= sd->add_mdef_class_count && sd->add_mdef_class_count < 10) {
+ sd->add_mdef_classid[sd->add_mdef_class_count] = type2;
+ sd->add_mdef_classrate[sd->add_mdef_class_count] += val;
+ sd->add_mdef_class_count++;
+ }
+ }
+ break;
+ case SP_HP_DRAIN_RATE:
+ if(!sd->state.lr_flag) {
+ sd->hp_drain_rate += type2;
+ sd->hp_drain_per += val;
+ }
+ else if(sd->state.lr_flag == 1) {
+ sd->hp_drain_rate_ += type2;
+ sd->hp_drain_per_ += val;
+ }
+ break;
+ case SP_SP_DRAIN_RATE:
+ if(!sd->state.lr_flag) {
+ sd->sp_drain_rate += type2;
+ sd->sp_drain_per += val;
+ }
+ else if(sd->state.lr_flag == 1) {
+ sd->sp_drain_rate_ += type2;
+ sd->sp_drain_per_ += val;
+ }
+ break;
+ case SP_WEAPON_COMA_ELE:
+ if(sd->state.lr_flag != 2)
+ sd->weapon_coma_ele[type2] += val;
+ break;
+ case SP_WEAPON_COMA_RACE:
+ if(sd->state.lr_flag != 2)
+ sd->weapon_coma_race[type2] += val;
+ break;
+ case SP_RANDOM_ATTACK_INCREASE: // [Valaris]
+ if(sd->state.lr_flag !=2){
+ sd->random_attack_increase_add = type2;
+ sd->random_attack_increase_per += val;
+ break;
+ } // end addition
+ default:
+ if(battle_config.error_log)
+ printf("pc_bonus2: unknown type %d %d %d!\n",type,type2,val);
+ break;
+ }
+ return 0;
+}
+
+int pc_bonus3(struct map_session_data *sd,int type,int type2,int type3,int val)
+{
+ int i;
+ switch(type){
+ case SP_ADD_MONSTER_DROP_ITEM:
+ if(sd->state.lr_flag != 2) {
+ for(i=0;i<sd->monster_drop_item_count;i++) {
+ if(sd->monster_drop_itemid[i] == type2) {
+ sd->monster_drop_race[i] |= 1<<type3;
+ if(sd->monster_drop_itemrate[i] < val)
+ sd->monster_drop_itemrate[i] = val;
+ break;
+ }
+ }
+ if(i >= sd->monster_drop_item_count && sd->monster_drop_item_count < 10) {
+ sd->monster_drop_itemid[sd->monster_drop_item_count] = type2;
+ sd->monster_drop_race[sd->monster_drop_item_count] |= 1<<type3;
+ sd->monster_drop_itemrate[sd->monster_drop_item_count] = val;
+ sd->monster_drop_item_count++;
+ }
+ }
+ break;
+ case SP_AUTOSPELL:
+ if(sd->state.lr_flag != 2){
+ sd->autospell_id = type2;
+ sd->autospell_lv = type3;
+ sd->autospell_rate = val;
+ }
+ break;
+ default:
+ if(battle_config.error_log)
+ printf("pc_bonus3: unknown type %d %d %d %d!\n",type,type2,type3,val);
+ break;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * スクリプトによるスキル所得
+ *------------------------------------------
+ */
+int pc_skill(struct map_session_data *sd,int id,int level,int flag)
+{
+ nullpo_retr(0, sd);
+
+ if(level>MAX_SKILL_LEVEL){
+ if(battle_config.error_log)
+ printf("support card skill only!\n");
+ return 0;
+ }
+ if(!flag && (sd->status.skill[id].id == id || level == 0)){ // クエスト所得ならここで条件を確認して送信する
+ sd->status.skill[id].lv=level;
+ pc_calcstatus(sd,0);
+ clif_skillinfoblock(sd);
+ }
+ else if(sd->status.skill[id].lv < level){ // 覚えられるがlvが小さいなら
+ if(sd->status.skill[id].id==id)
+ sd->status.skill[id].flag=sd->status.skill[id].lv+2; // lvを記憶
+ else {
+ sd->status.skill[id].id=id;
+ sd->status.skill[id].flag=1; // cardスキルとする
+ }
+ sd->status.skill[id].lv=level;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * カード挿入
+ *------------------------------------------
+ */
+int pc_insert_card(struct map_session_data *sd,int idx_card,int idx_equip)
+{
+ nullpo_retr(0, sd);
+
+ if(idx_card >= 0 && idx_card < MAX_INVENTORY && idx_equip >= 0 && idx_equip < MAX_INVENTORY && sd->inventory_data[idx_card]) {
+ int i;
+ int nameid=sd->status.inventory[idx_equip].nameid;
+ int cardid=sd->status.inventory[idx_card].nameid;
+ int ep=sd->inventory_data[idx_card]->equip;
+
+ if( nameid <= 0 || sd->inventory_data[idx_equip] == NULL ||
+ (sd->inventory_data[idx_equip]->type!=4 && sd->inventory_data[idx_equip]->type!=5)|| // 装 備じゃない
+ ( sd->status.inventory[idx_equip].identify==0 ) || // 未鑑定
+ ( sd->status.inventory[idx_equip].card[0]==0x00ff) || // 製造武器
+ ( sd->status.inventory[idx_equip].card[0]==0x00fe) ||
+ ( (sd->inventory_data[idx_equip]->equip&ep)==0 ) || // 装 備個所違い
+ ( sd->inventory_data[idx_equip]->type==4 && ep==32) || // 両 手武器と盾カード
+ ( sd->status.inventory[idx_equip].card[0]==(short)0xff00) || sd->status.inventory[idx_equip].equip){
+
+ clif_insert_card(sd,idx_equip,idx_card,1);
+ return 0;
+ }
+ for(i=0;i<sd->inventory_data[idx_equip]->slot;i++){
+ if( sd->status.inventory[idx_equip].card[i] == 0){
+ // 空きスロットがあったので差し込む
+ sd->status.inventory[idx_equip].card[i]=cardid;
+
+ // カードは減らす
+ clif_insert_card(sd,idx_equip,idx_card,0);
+ pc_delitem(sd,idx_card,1,1);
+ return 0;
+ }
+ }
+ }
+ else
+ clif_insert_card(sd,idx_equip,idx_card,1);
+
+ return 0;
+}
+
+//
+// アイテム物
+//
+
+/*==========================================
+ * スキルによる買い値修正
+ *------------------------------------------
+ */
+int pc_modifybuyvalue(struct map_session_data *sd,int orig_value)
+{
+ int skill,val = orig_value,rate1 = 0,rate2 = 0;
+ if((skill=pc_checkskill(sd,MC_DISCOUNT))>0) // ディスカウント
+ rate1 = 5+skill*2-((skill==10)? 1:0);
+ if((skill=pc_checkskill(sd,RG_COMPULSION))>0) // コムパルションディスカウント
+ rate2 = 5+skill*4;
+ if(rate1 < rate2) rate1 = rate2;
+ if(rate1)
+ val = (int)((double)orig_value*(double)(100-rate1)/100.);
+ if(val < 0) val = 0;
+ if(orig_value > 0 && val < 1) val = 1;
+
+ return val;
+}
+
+/*==========================================
+ * スキルによる売り値修正
+ *------------------------------------------
+ */
+int pc_modifysellvalue(struct map_session_data *sd,int orig_value)
+{
+ int skill,val = orig_value,rate = 0;
+ if((skill=pc_checkskill(sd,MC_OVERCHARGE))>0) // オーバーチャージ
+ rate = 5+skill*2-((skill==10)? 1:0);
+ if(rate)
+ val = (int)((double)orig_value*(double)(100+rate)/100.);
+ if(val < 0) val = 0;
+ if(orig_value > 0 && val < 1) val = 1;
+
+ return val;
+}
+
+/*==========================================
+ * アイテムを買った時に、新しいアイテム欄を使うか、
+ * 3万個制限にかかるか確認
+ *------------------------------------------
+ */
+int pc_checkadditem(struct map_session_data *sd,int nameid,int amount)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if(itemdb_isequip(nameid))
+ return ADDITEM_NEW;
+
+ for(i=0;i<MAX_INVENTORY;i++){
+ if(sd->status.inventory[i].nameid==nameid){
+ if(sd->status.inventory[i].amount+amount > MAX_AMOUNT)
+ return ADDITEM_OVERAMOUNT;
+ return ADDITEM_EXIST;
+ }
+ }
+
+ if(amount > MAX_AMOUNT)
+ return ADDITEM_OVERAMOUNT;
+ return ADDITEM_NEW;
+}
+
+/*==========================================
+ * 空きアイテム欄の個数
+ *------------------------------------------
+ */
+int pc_inventoryblank(struct map_session_data *sd)
+{
+ int i,b;
+
+ nullpo_retr(0, sd);
+
+ for(i=0,b=0;i<MAX_INVENTORY;i++){
+ if(sd->status.inventory[i].nameid==0)
+ b++;
+ }
+
+ return b;
+}
+
+/*==========================================
+ * お金を払う
+ *------------------------------------------
+ */
+int pc_payzeny(struct map_session_data *sd,int zeny)
+{
+ double z;
+
+ nullpo_retr(0, sd);
+
+ z = (double)sd->status.zeny;
+ if(sd->status.zeny<zeny || z - (double)zeny > MAX_ZENY)
+ return 1;
+ sd->status.zeny-=zeny;
+ clif_updatestatus(sd,SP_ZENY);
+
+ return 0;
+}
+
+/*==========================================
+ * お金を得る
+ *------------------------------------------
+ */
+int pc_getzeny(struct map_session_data *sd,int zeny)
+{
+ double z;
+
+ nullpo_retr(0, sd);
+
+ z = (double)sd->status.zeny;
+ if(z + (double)zeny > MAX_ZENY) {
+ zeny = 0;
+ sd->status.zeny = MAX_ZENY;
+ }
+ sd->status.zeny+=zeny;
+ clif_updatestatus(sd,SP_ZENY);
+
+ return 0;
+}
+
+/*==========================================
+ * アイテムを探して、インデックスを返す
+ *------------------------------------------
+ */
+int pc_search_inventory(struct map_session_data *sd,int item_id)
+{
+ int i;
+
+ nullpo_retr(-1, sd);
+
+ for(i=0;i<MAX_INVENTORY;i++) {
+ if(sd->status.inventory[i].nameid == item_id &&
+ (sd->status.inventory[i].amount > 0 || item_id == 0))
+ return i;
+ }
+
+ return -1;
+}
+
+/*==========================================
+ * アイテム追加。個数のみitem構造体の数字を無視
+ *------------------------------------------
+ */
+int pc_additem(struct map_session_data *sd,struct item *item_data,int amount)
+{
+ struct item_data *data;
+ int i,w;
+
+ nullpo_retr(1, sd);
+ nullpo_retr(1, item_data);
+
+ if(item_data->nameid <= 0 || amount <= 0)
+ return 1;
+ data = itemdb_search(item_data->nameid);
+ if((w = data->weight*amount) + sd->weight > sd->max_weight)
+ return 2;
+
+ i = MAX_INVENTORY;
+
+ if(!itemdb_isequip2(data)){
+ // 装 備品ではないので、既所有品なら個数のみ変化させる
+ for(i=0;i<MAX_INVENTORY;i++)
+ if(sd->status.inventory[i].nameid == item_data->nameid &&
+ sd->status.inventory[i].card[0] == item_data->card[0] && sd->status.inventory[i].card[1] == item_data->card[1] &&
+ sd->status.inventory[i].card[2] == item_data->card[2] && sd->status.inventory[i].card[3] == item_data->card[3]) {
+ if(sd->status.inventory[i].amount+amount > MAX_AMOUNT)
+ return 5;
+ sd->status.inventory[i].amount+=amount;
+ clif_additem(sd,i,amount,0);
+ break;
+ }
+ }
+ if(i >= MAX_INVENTORY){
+ // 装 備品か未所有品だったので空き欄へ追加
+ i = pc_search_inventory(sd,0);
+ if(i >= 0) {
+ memcpy(&sd->status.inventory[i],item_data,sizeof(sd->status.inventory[0]));
+ sd->status.inventory[i].amount=amount;
+ sd->inventory_data[i]=data;
+ clif_additem(sd,i,amount,0);
+ }
+ else return 4;
+ }
+ sd->weight += w;
+ clif_updatestatus(sd,SP_WEIGHT);
+
+ return 0;
+}
+
+/*==========================================
+ * アイテムを減らす
+ *------------------------------------------
+ */
+int pc_delitem(struct map_session_data *sd,int n,int amount,int type)
+{
+ nullpo_retr(1, sd);
+
+ if(sd->status.inventory[n].nameid==0 || amount <= 0 || sd->status.inventory[n].amount<amount || sd->inventory_data[n] == NULL)
+ return 1;
+
+ sd->status.inventory[n].amount -= amount;
+ sd->weight -= sd->inventory_data[n]->weight*amount ;
+ if(sd->status.inventory[n].amount<=0){
+ if(sd->status.inventory[n].equip)
+ pc_unequipitem(sd,n,0);
+ memset(&sd->status.inventory[n],0,sizeof(sd->status.inventory[0]));
+ sd->inventory_data[n] = NULL;
+ }
+ if(!(type&1))
+ clif_delitem(sd,n,amount);
+ if(!(type&2))
+ clif_updatestatus(sd,SP_WEIGHT);
+
+ return 0;
+}
+
+/*==========================================
+ * アイテムを落す
+ *------------------------------------------
+ */
+int pc_dropitem(struct map_session_data *sd,int n,int amount)
+{
+ nullpo_retr(1, sd);
+
+ if (sd->status.inventory[n].nameid <= 0 ||
+ sd->status.inventory[n].amount < amount ||
+ sd->trade_partner != 0 || sd->vender_id != 0 ||
+ sd->status.inventory[n].amount <= 0)
+ return 1;
+ map_addflooritem(&sd->status.inventory[n], amount, sd->bl.m, sd->bl.x, sd->bl.y, NULL, NULL, NULL, 0);
+ pc_delitem(sd, n, amount, 0);
+
+ return 0;
+}
+
+/*==========================================
+ * アイテムを拾う
+ *------------------------------------------
+ */
+int pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem)
+{
+ int flag;
+ unsigned int tick = gettick();
+ struct map_session_data *first_sd = NULL,*second_sd = NULL,*third_sd = NULL;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, fitem);
+
+ if(fitem->first_get_id > 0) {
+ first_sd = map_id2sd(fitem->first_get_id);
+ if(tick < fitem->first_get_tick) {
+ if(fitem->first_get_id != sd->bl.id && !(first_sd && first_sd->status.party_id == sd->status.party_id)) {
+ clif_additem(sd,0,0,6);
+ return 0;
+ }
+ }
+ else if(fitem->second_get_id > 0) {
+ second_sd = map_id2sd(fitem->second_get_id);
+ if(tick < fitem->second_get_tick) {
+ if(fitem->first_get_id != sd->bl.id && fitem->second_get_id != sd->bl.id &&
+ !(first_sd && first_sd->status.party_id == sd->status.party_id) && !(second_sd && second_sd->status.party_id == sd->status.party_id)) {
+ clif_additem(sd,0,0,6);
+ return 0;
+ }
+ }
+ else if(fitem->third_get_id > 0) {
+ third_sd = map_id2sd(fitem->third_get_id);
+ if(tick < fitem->third_get_tick) {
+ if(fitem->first_get_id != sd->bl.id && fitem->second_get_id != sd->bl.id && fitem->third_get_id != sd->bl.id &&
+ !(first_sd && first_sd->status.party_id == sd->status.party_id) && !(second_sd && second_sd->status.party_id == sd->status.party_id) &&
+ !(third_sd && third_sd->status.party_id == sd->status.party_id)) {
+ clif_additem(sd,0,0,6);
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ if((flag = pc_additem(sd,&fitem->item_data,fitem->item_data.amount)))
+ // 重量overで取得失敗
+ clif_additem(sd,0,0,flag);
+ else {
+ /* 取得成功 */
+ if(sd->attacktimer != -1)
+ pc_stopattack(sd);
+ clif_takeitem(&sd->bl,&fitem->bl);
+ map_clearflooritem(fitem->bl.id);
+ }
+ return 0;
+}
+
+int pc_isUseitem(struct map_session_data *sd,int n)
+{
+ struct item_data *item;
+ int nameid;
+
+ nullpo_retr(0, sd);
+
+ item = sd->inventory_data[n];
+ nameid = sd->status.inventory[n].nameid;
+
+ if(item == NULL)
+ return 0;
+ if((nameid == 605) && map[sd->bl.m].flag.gvg)
+ return 0;
+ if(nameid == 601 && (map[sd->bl.m].flag.noteleport || map[sd->bl.m].flag.gvg)) {
+ clif_skill_teleportmessage(sd,0);
+ return 0;
+ }
+ if(nameid == 602 && map[sd->bl.m].flag.noreturn)
+ return 0;
+ if(nameid == 604 && (map[sd->bl.m].flag.nobranch || map[sd->bl.m].flag.gvg))
+ return 0;
+ if(item->sex != 2 && sd->status.sex != item->sex)
+ return 0;
+ if(item->elv > 0 && sd->status.base_level < item->elv)
+ return 0;
+ if(((sd->status.class==13 || sd->status.class==4014) && ((1<<7)&item->class) == 0) || // have mounted classes use unmounted items [Valaris]
+ ((sd->status.class==21 || sd->status.class==4022) && ((1<<14)&item->class) == 0))
+ return 0;
+ if(sd->status.class!=13 && sd->status.class!=4014 && sd->status.class!=21 && sd->status.class!=4022)
+ if((sd->status.class<=4000 && ((1<<sd->status.class)&item->class) == 0) || (sd->status.class>4000 && sd->status.class<4023 && ((1<<(sd->status.class-4001))&item->class) == 0) ||
+ (sd->status.class>=4023 && ((1<<(sd->status.class-4023))&item->class) == 0))
+ return 0;
+
+#ifndef TXT_ONLY
+ if((log_config.branch > 0) && (nameid == 604))
+ log_branch(sd);
+#endif
+
+ return 1;
+}
+
+/*==========================================
+ * アイテムを使う
+ *------------------------------------------
+ */
+int pc_useitem(struct map_session_data *sd,int n)
+{
+ int nameid,amount;
+
+ nullpo_retr(1, sd);
+
+ if(n >=0 && n < MAX_INVENTORY) {
+ nameid = sd->status.inventory[n].nameid;
+ amount = sd->status.inventory[n].amount;
+ if(sd->status.inventory[n].nameid <= 0 ||
+ sd->status.inventory[n].amount <= 0 ||
+ sd->sc_data[SC_BERSERK].timer!=-1 ||
+ !pc_isUseitem(sd,n) ) {
+ clif_useitemack(sd,n,0,0);
+ return 1;
+ }
+ if(sd->inventory_data[n])
+ run_script(sd->inventory_data[n]->use_script,0,sd->bl.id,0);
+
+ clif_useitemack(sd,n,amount-1,1);
+ pc_delitem(sd,n,1,1);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * カートアイテム追加。個数のみitem構造体の数字を無視
+ *------------------------------------------
+ */
+int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amount)
+{
+ struct item_data *data;
+ int i,w;
+
+ nullpo_retr(1, sd);
+ nullpo_retr(1, item_data);
+
+ if(item_data->nameid <= 0 || amount <= 0)
+ return 1;
+ data = itemdb_search(item_data->nameid);
+
+ if((w=data->weight*amount) + sd->cart_weight > sd->cart_max_weight)
+ return 1;
+
+ i=MAX_CART;
+ if(!itemdb_isequip2(data)){
+ // 装 備品ではないので、既所有品なら個数のみ変化させる
+ for(i=0;i<MAX_CART;i++){
+ if(sd->status.cart[i].nameid==item_data->nameid &&
+ sd->status.cart[i].card[0] == item_data->card[0] && sd->status.cart[i].card[1] == item_data->card[1] &&
+ sd->status.cart[i].card[2] == item_data->card[2] && sd->status.cart[i].card[3] == item_data->card[3]){
+ if(sd->status.cart[i].amount+amount > MAX_AMOUNT)
+ return 1;
+ sd->status.cart[i].amount+=amount;
+ clif_cart_additem(sd,i,amount,0);
+ break;
+ }
+ }
+ }
+ if(i >= MAX_CART){
+ // 装 備品か未所有品だったので空き欄へ追加
+ for(i=0;i<MAX_CART;i++){
+ if(sd->status.cart[i].nameid==0){
+ memcpy(&sd->status.cart[i],item_data,sizeof(sd->status.cart[0]));
+ sd->status.cart[i].amount=amount;
+ sd->cart_num++;
+ clif_cart_additem(sd,i,amount,0);
+ break;
+ }
+ }
+ if(i >= MAX_CART)
+ return 1;
+ }
+ sd->cart_weight += w;
+ clif_updatestatus(sd,SP_CARTINFO);
+
+ return 0;
+}
+
+/*==========================================
+ * カートアイテムを減らす
+ *------------------------------------------
+ */
+int pc_cart_delitem(struct map_session_data *sd,int n,int amount,int type)
+{
+ nullpo_retr(1, sd);
+
+ if(sd->status.cart[n].nameid==0 ||
+ sd->status.cart[n].amount<amount)
+ return 1;
+
+ sd->status.cart[n].amount -= amount;
+ sd->cart_weight -= itemdb_weight(sd->status.cart[n].nameid)*amount ;
+ if(sd->status.cart[n].amount <= 0){
+ memset(&sd->status.cart[n],0,sizeof(sd->status.cart[0]));
+ sd->cart_num--;
+ }
+ if(!type) {
+ clif_cart_delitem(sd,n,amount);
+ clif_updatestatus(sd,SP_CARTINFO);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * カートへアイテム移動
+ *------------------------------------------
+ */
+int pc_putitemtocart(struct map_session_data *sd,int idx,int amount) {
+ struct item *item_data;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, item_data = &sd->status.inventory[idx]);
+
+ if (item_data->nameid==0 || item_data->amount<amount || sd->vender_id)
+ return 1;
+ if (pc_cart_additem(sd,item_data,amount) == 0)
+ return pc_delitem(sd,idx,amount,0);
+
+ return 1;
+}
+
+/*==========================================
+ * カート内のアイテム数確認(個数の差分を返す)
+ *------------------------------------------
+ */
+int pc_cartitem_amount(struct map_session_data *sd,int idx,int amount)
+{
+ struct item *item_data;
+
+ nullpo_retr(-1, sd);
+ nullpo_retr(-1, item_data=&sd->status.cart[idx]);
+
+ if( item_data->nameid==0 || !item_data->amount)
+ return -1;
+ return item_data->amount-amount;
+}
+/*==========================================
+ * カートからアイテム移動
+ *------------------------------------------
+ */
+
+int pc_getitemfromcart(struct map_session_data *sd,int idx,int amount)
+{
+ struct item *item_data;
+ int flag;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, item_data=&sd->status.cart[idx]);
+
+ if( item_data->nameid==0 || item_data->amount<amount || sd->vender_id )
+ return 1;
+ if((flag = pc_additem(sd,item_data,amount)) == 0)
+ return pc_cart_delitem(sd,idx,amount,0);
+
+ clif_additem(sd,0,0,flag);
+ return 1;
+}
+
+/*==========================================
+ * アイテム鑑定
+ *------------------------------------------
+ */
+int pc_item_identify(struct map_session_data *sd,int idx)
+{
+ int flag=1;
+
+ nullpo_retr(0, sd);
+
+ if(idx >= 0 && idx < MAX_INVENTORY) {
+ if(sd->status.inventory[idx].nameid > 0 && sd->status.inventory[idx].identify == 0 ){
+ flag=0;
+ sd->status.inventory[idx].identify=1;
+ }
+ clif_item_identified(sd,idx,flag);
+ }
+ else
+ clif_item_identified(sd,idx,flag);
+
+ return !flag;
+}
+
+/*==========================================
+ * スティル品公開
+ *------------------------------------------
+ */
+int pc_show_steal(struct block_list *bl,va_list ap)
+{
+ struct map_session_data *sd;
+ int itemid;
+ int type;
+
+ struct item_data *item=NULL;
+ char output[100];
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, sd=va_arg(ap,struct map_session_data *));
+
+ itemid=va_arg(ap,int);
+ type=va_arg(ap,int);
+
+ if(!type){
+ if((item=itemdb_exists(itemid))==NULL)
+ sprintf(output,"%s stole an Unknown_Item.",sd->status.name);
+ else
+ sprintf(output,"%s stole %s.",sd->status.name,item->jname);
+ clif_displaymessage( ((struct map_session_data *)bl)->fd, output);
+ }else{
+ sprintf(output,"%s has not stolen the item because of being overweight.",sd->status.name);
+ clif_displaymessage( ((struct map_session_data *)bl)->fd, output);
+ }
+
+ return 0;
+}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+//** pc.c: Small Steal Item fix by fritz
+int pc_steal_item(struct map_session_data *sd,struct block_list *bl)
+{
+ if(sd != NULL && bl != NULL && bl->type == BL_MOB) {
+ int i,skill,rate,itemid,flag, count;
+ struct mob_data *md;
+ md=(struct mob_data *)bl;
+ if(!md->state.steal_flag && mob_db[md->class].mexp <= 0 && !(mob_db[md->class].mode&0x20) && md->sc_data[SC_STONE].timer == -1 && md->sc_data[SC_FREEZE].timer == -1 &&
+ (!(md->class>1324 && md->class<1364))) // prevent stealing from treasure boxes [Valaris]
+ {
+ skill = sd->paramc[4] - mob_db[md->class].dex + pc_checkskill(sd,TF_STEAL) + 10;
+
+ if(0 < skill)
+ {
+ for(count = 8; count <= 8 && count != 0; count--)
+ {
+ i = rand()%8;
+ itemid = mob_db[md->class].dropitem[i].nameid;
+
+ if(itemid > 0 && itemdb_type(itemid) != 6)
+ {
+ rate = (mob_db[md->class].dropitem[i].p / battle_config.item_rate_common * 100 * skill)/100;
+
+ if(rand()%10000 < rate)
+ {
+ struct item tmp_item;
+ memset(&tmp_item,0,sizeof(tmp_item));
+ tmp_item.nameid = itemid;
+ tmp_item.amount = 1;
+ tmp_item.identify = 1;
+ flag = pc_additem(sd,&tmp_item,1);
+ if(battle_config.show_steal_in_same_party)
+ {
+ party_foreachsamemap(pc_show_steal,sd,1,sd,tmp_item.nameid,0);
+ }
+
+ if(flag)
+ {
+ if(battle_config.show_steal_in_same_party)
+ {
+ party_foreachsamemap(pc_show_steal,sd,1,sd,tmp_item.nameid,1);
+ }
+
+ clif_additem(sd,0,0,flag);
+ }
+ md->state.steal_flag = 1;
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int pc_steal_coin(struct map_session_data *sd,struct block_list *bl)
+{
+ if(sd != NULL && bl != NULL && bl->type == BL_MOB) {
+ int rate,skill;
+ struct mob_data *md=(struct mob_data *)bl;
+ if(md && !md->state.steal_coin_flag && md->sc_data && md->sc_data[SC_STONE].timer == -1 && md->sc_data[SC_FREEZE].timer == -1) {
+ skill = pc_checkskill(sd,RG_STEALCOIN)*10;
+ rate = skill + (sd->status.base_level - mob_db[md->class].lv)*3 + sd->paramc[4]*2 + sd->paramc[5]*2;
+ if(rand()%1000 < rate) {
+ pc_getzeny(sd,mob_db[md->class].lv*10 + rand()%100);
+ md->state.steal_coin_flag = 1;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+//
+//
+//
+/*==========================================
+ * PCの位置設定
+ *------------------------------------------
+ */
+int pc_setpos(struct map_session_data *sd,char *mapname_org,int x,int y,int clrtype)
+{
+ char mapname[24];
+ int m=0,c=0,disguise=0;
+
+ nullpo_retr(0, sd);
+
+ if(sd->chatID) // チャットから出る
+ chat_leavechat(sd);
+ if(sd->trade_partner) // 取引を中断する
+ trade_tradecancel(sd);
+ if(sd->state.storage_flag)
+ storage_guild_storage_quit(sd,0);
+ else
+ storage_storage_quit(sd); // 倉庫を開いてるなら保存する
+
+ if(sd->party_invite>0) // パーティ勧誘を拒否する
+ party_reply_invite(sd,sd->party_invite_account,0);
+ if(sd->guild_invite>0) // ギルド勧誘を拒否する
+ guild_reply_invite(sd,sd->guild_invite,0);
+ if(sd->guild_alliance>0) // ギルド同盟勧誘を拒否する
+ guild_reply_reqalliance(sd,sd->guild_alliance_account,0);
+
+ skill_castcancel(&sd->bl,0); // 詠唱中断
+ pc_stop_walking(sd,0); // 歩行中断
+ pc_stopattack(sd); // 攻撃中断
+
+ if(pc_issit(sd)) {
+ pc_setstand(sd);
+ skill_gangsterparadise(sd,0);
+ }
+
+ if(sd->sc_data[SC_TRICKDEAD].timer != -1)
+ skill_status_change_end(&sd->bl, SC_TRICKDEAD, -1);
+ if(sd->status.option&2)
+ skill_status_change_end(&sd->bl, SC_HIDING, -1);
+ if(sd->status.option&4)
+ skill_status_change_end(&sd->bl, SC_CLOAKING, -1);
+ if(sd->status.option&16386)
+ skill_status_change_end(&sd->bl, SC_CHASEWALK, -1);
+ if(sd->sc_data[SC_BLADESTOP].timer!=-1)
+ skill_status_change_end(&sd->bl,SC_BLADESTOP,-1);
+ if(sd->sc_data[SC_DANCING].timer!=-1) // clear dance effect when warping [Valaris]
+ skill_stop_dancing(&sd->bl,0);
+
+ if(sd->status.pet_id > 0 && sd->pd && sd->pet.intimate > 0) {
+ pet_stopattack(sd->pd);
+ pet_changestate(sd->pd,MS_IDLE,0);
+ }
+
+ if(sd->disguise) { // clear disguises when warping [Valaris]
+ clif_clearchar(&sd->bl, 9);
+ disguise=sd->disguise;
+ sd->disguise=0;
+ }
+
+ memcpy(mapname,mapname_org,24);
+ mapname[16]=0;
+ if(strstr(mapname,".gat")==NULL && strlen(mapname)<16){
+ strcat(mapname,".gat");
+ }
+
+ m=map_mapname2mapid(mapname);
+ if(m<0){
+ if(sd->mapname[0]){
+ int ip,port;
+ if(map_mapname2ipport(mapname,&ip,&port)==0){
+ skill_stop_dancing(&sd->bl,1);
+ skill_unit_out_all(&sd->bl,gettick(),1);
+ clif_clearchar_area(&sd->bl,clrtype&0xffff);
+ skill_gangsterparadise(sd,0);
+ map_delblock(&sd->bl);
+ if(sd->status.pet_id > 0 && sd->pd) {
+ if(sd->pd->bl.m != m && sd->pet.intimate <= 0) {
+ pet_remove_map(sd);
+ intif_delete_petdata(sd->status.pet_id);
+ sd->status.pet_id = 0;
+ sd->pd = NULL;
+ sd->petDB = NULL;
+ if(battle_config.pet_status_support)
+ pc_calcstatus(sd,2);
+ }
+ else if(sd->pet.intimate > 0) {
+ pet_stopattack(sd->pd);
+ pet_changestate(sd->pd,MS_IDLE,0);
+ clif_clearchar_area(&sd->pd->bl,clrtype&0xffff);
+ map_delblock(&sd->pd->bl);
+ }
+ }
+ memcpy(sd->mapname,mapname,24);
+ sd->bl.x=x;
+ sd->bl.y=y;
+ sd->state.waitingdisconnect=1;
+ pc_makesavestatus(sd);
+ if(sd->status.pet_id > 0 && sd->pd)
+ intif_save_petdata(sd->status.account_id,&sd->pet);
+ chrif_save(sd);
+ storage_storage_save(sd);
+ chrif_changemapserver(sd, mapname, x, y, ip, port);
+ return 0;
+ }
+ }
+#if 0
+ clif_authfail_fd(sd->fd,0); // cancel
+ clif_setwaitclose(sd->fd);
+#endif
+ return 1;
+ }
+
+ if(x <0 || x >= map[m].xs || y <0 || y >= map[m].ys)
+ x=y=0;
+ if((x==0 && y==0) || (c=read_gat(m,x,y))==1 || c==5){
+ if(x||y) {
+ if(battle_config.error_log)
+ printf("stacked (%d,%d)\n",x,y);
+ }
+ do {
+ x=rand()%(map[m].xs-2)+1;
+ y=rand()%(map[m].ys-2)+1;
+ } while((c=read_gat(m,x,y))==1 || c==5);
+ }
+
+ if(sd->mapname[0] && sd->bl.prev != NULL){
+ skill_unit_out_all(&sd->bl,gettick(),1);
+ clif_clearchar_area(&sd->bl,clrtype&0xffff);
+ skill_gangsterparadise(sd,0);
+ map_delblock(&sd->bl);
+ // pet
+ if(sd->status.pet_id > 0 && sd->pd) {
+ if(sd->pd->bl.m != m && sd->pet.intimate <= 0) {
+ pet_remove_map(sd);
+ intif_delete_petdata(sd->status.pet_id);
+ sd->status.pet_id = 0;
+ sd->pd = NULL;
+ sd->petDB = NULL;
+ if(battle_config.pet_status_support)
+ pc_calcstatus(sd,2);
+ pc_makesavestatus(sd);
+ chrif_save(sd);
+ storage_storage_save(sd);
+ }
+ else if(sd->pet.intimate > 0) {
+ pet_stopattack(sd->pd);
+ pet_changestate(sd->pd,MS_IDLE,0);
+ clif_clearchar_area(&sd->pd->bl,clrtype&0xffff);
+ map_delblock(&sd->pd->bl);
+ }
+ }
+ clif_changemap(sd,map[m].name,x,y); // [MouseJstr]
+ }
+
+ if(disguise) // disguise teleport fix [Valaris]
+ sd->disguise=disguise;
+
+ memcpy(sd->mapname,mapname,24);
+ sd->bl.m = m;
+ sd->to_x = x;
+ sd->to_y = y;
+
+ // moved and changed dance effect stopping
+
+ sd->bl.x = x;
+ sd->bl.y = y;
+
+ if(sd->status.pet_id > 0 && sd->pd && sd->pet.intimate > 0) {
+ sd->pd->bl.m = m;
+ sd->pd->bl.x = sd->pd->to_x = x;
+ sd->pd->bl.y = sd->pd->to_y = y;
+ sd->pd->dir = sd->dir;
+ }
+
+// map_addblock(&sd->bl); /// ブロック登録とspawnは
+// clif_spawnpc(sd);
+
+ return 0;
+}
+
+/*==========================================
+ * PCのランダムワープ
+ *------------------------------------------
+ */
+int pc_randomwarp(struct map_session_data *sd, int type) {
+ int x,y,c,i=0;
+ int m;
+
+ nullpo_retr(0, sd);
+
+ m=sd->bl.m;
+
+ if (map[sd->bl.m].flag.noteleport) // テレポート禁止
+ return 0;
+
+ do{
+ x=rand()%(map[m].xs-2)+1;
+ y=rand()%(map[m].ys-2)+1;
+ } while (((c=read_gat(m,x,y)) == 1 || c == 5) && (i++) < 1000);
+
+ if (i < 1000)
+ pc_setpos(sd,map[m].name,x,y,type);
+
+ return 0;
+}
+
+/*==========================================
+ * 現在位置のメモ
+ *------------------------------------------
+ */
+int pc_memo(struct map_session_data *sd, int i) {
+ int skill;
+ int j;
+
+ nullpo_retr(0, sd);
+
+ skill = pc_checkskill(sd, AL_WARP);
+
+ if (i >= MIN_PORTAL_MEMO)
+ i -= MIN_PORTAL_MEMO;
+ else if (map[sd->bl.m].flag.nomemo || (map[sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd))) {
+ clif_skill_teleportmessage(sd, 1);
+ return 0;
+ }
+
+ if (skill < 1) {
+ clif_skill_memo(sd,2);
+ }
+
+ if (skill < 2 || i < -1 || i > 2) {
+ clif_skill_memo(sd, 1);
+ return 0;
+ }
+
+ for(j = 0 ; j < 3; j++) {
+ if (strcmp(sd->status.memo_point[j].map, map[sd->bl.m].name) == 0) {
+ i = j;
+ break;
+ }
+ }
+
+ if (i == -1) {
+ for(i = skill - 3; i >= 0; i--) {
+ memcpy(&sd->status.memo_point[i+1],&sd->status.memo_point[i],
+ sizeof(struct point));
+ }
+ i = 0;
+ }
+ memcpy(sd->status.memo_point[i].map, map[sd->bl.m].name, 24);
+ sd->status.memo_point[i].x = sd->bl.x;
+ sd->status.memo_point[i].y = sd->bl.y;
+
+ clif_skill_memo(sd, 0);
+
+ return 1;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int pc_can_reach(struct map_session_data *sd,int x,int y)
+{
+ struct walkpath_data wpd;
+
+ nullpo_retr(0, sd);
+
+ if( sd->bl.x==x && sd->bl.y==y ) // 同じマス
+ return 1;
+
+ // 障害物判定
+ wpd.path_len=0;
+ wpd.path_pos=0;
+ wpd.path_half=0;
+ return (path_search(&wpd,sd->bl.m,sd->bl.x,sd->bl.y,x,y,0)!=-1)?1:0;
+}
+
+//
+// 歩 行物
+//
+/*==========================================
+ * 次の1歩にかかる時間を計算
+ *------------------------------------------
+ */
+static int calc_next_walk_step(struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+
+ if(sd->walkpath.path_pos>=sd->walkpath.path_len)
+ return -1;
+ if(sd->walkpath.path[sd->walkpath.path_pos]&1)
+ return sd->speed*14/10;
+
+ return sd->speed;
+}
+
+/*==========================================
+ * 半歩進む(timer関数)
+ *------------------------------------------
+ */
+static int pc_walk(int tid,unsigned int tick,int id,int data)
+{
+ struct map_session_data *sd;
+ int i,ctype;
+ int moveblock;
+ int x,y,dx,dy;
+
+ sd=map_id2sd(id);
+ if(sd==NULL)
+ return 0;
+
+ if(sd->walktimer != tid){
+ if(battle_config.error_log)
+ printf("pc_walk %d != %d\n",sd->walktimer,tid);
+ return 0;
+ }
+ sd->walktimer=-1;
+ if(sd->walkpath.path_pos>=sd->walkpath.path_len || sd->walkpath.path_pos!=data)
+ return 0;
+
+ //歩いたので息吹のタイマーを初期化
+ sd->inchealspirithptick = 0;
+ sd->inchealspiritsptick = 0;
+
+ sd->walkpath.path_half ^= 1;
+ if(sd->walkpath.path_half==0){ // マス目中心へ到着
+ sd->walkpath.path_pos++;
+ if(sd->state.change_walk_target){
+ pc_walktoxy_sub(sd);
+ return 0;
+ }
+ } else { // マス目境界へ到着
+ if(sd->walkpath.path[sd->walkpath.path_pos]>=8)
+ return 1;
+
+ x = sd->bl.x;
+ y = sd->bl.y;
+ ctype = map_getcell(sd->bl.m,x,y);
+ if(ctype == 1 || ctype == 5) {
+ pc_stop_walking(sd,1);
+ return 0;
+ }
+ sd->dir=sd->head_dir=sd->walkpath.path[sd->walkpath.path_pos];
+ dx = dirx[(int)sd->dir];
+ dy = diry[(int)sd->dir];
+ ctype = map_getcell(sd->bl.m,x+dx,y+dy);
+ if(ctype == 1 || ctype == 5) {
+ pc_walktoxy_sub(sd);
+ return 0;
+ }
+
+ moveblock = ( x/BLOCK_SIZE != (x+dx)/BLOCK_SIZE || y/BLOCK_SIZE != (y+dy)/BLOCK_SIZE);
+
+ sd->walktimer = 1;
+ map_foreachinmovearea(clif_pcoutsight,sd->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,0,sd);
+
+ x += dx;
+ y += dy;
+
+ if(moveblock) map_delblock(&sd->bl);
+ sd->bl.x = x;
+ sd->bl.y = y;
+ if(moveblock) map_addblock(&sd->bl);
+
+ if(sd->sc_data[SC_DANCING].timer!=-1)
+ skill_unit_move_unit_group((struct skill_unit_group *)sd->sc_data[SC_DANCING].val2,sd->bl.m,dx,dy);
+
+ map_foreachinmovearea(clif_pcinsight,sd->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,-dx,-dy,0,sd);
+ sd->walktimer = -1;
+
+ if(sd->status.party_id>0){ // パーティのHP情報通知検査
+ struct party *p=party_search(sd->status.party_id);
+ if(p!=NULL){
+ int p_flag=0;
+ map_foreachinmovearea(party_send_hp_check,sd->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,-dx,-dy,BL_PC,sd->status.party_id,&p_flag);
+ if(p_flag)
+ sd->party_hp=-1;
+ }
+ }
+ if(sd->status.option&4) // クローキングの消滅検査
+ skill_check_cloaking(&sd->bl);
+ /* ディボーション検査 */
+ for(i=0;i<5;i++)
+ if(sd->dev.val1[i]){
+ skill_devotion3(&sd->bl,sd->dev.val1[i]);
+ break;
+ }
+ /* 被ディボーション検査 */
+ if( sd->sc_data && sd->sc_data[SC_DEVOTION].val1){
+ skill_devotion2(&sd->bl,sd->sc_data[SC_DEVOTION].val1);
+ }
+
+ skill_unit_move(&sd->bl,tick,1); // スキルユニットの検査
+
+ if(map_getcell(sd->bl.m,x,y)&0x80)
+ npc_touch_areanpc(sd,sd->bl.m,x,y);
+ else
+ sd->areanpc_id=0;
+ }
+ if((i=calc_next_walk_step(sd))>0) {
+ i = i>>1;
+ if(i < 1 && sd->walkpath.path_half == 0)
+ i = 1;
+ sd->walktimer=add_timer(tick+i,pc_walk,id,sd->walkpath.path_pos);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 移動可能か確認して、可能なら歩行開始
+ *------------------------------------------
+ */
+static int pc_walktoxy_sub(struct map_session_data *sd)
+{
+ struct walkpath_data wpd;
+ int i;
+
+ nullpo_retr(1, sd);
+
+ if(path_search(&wpd,sd->bl.m,sd->bl.x,sd->bl.y,sd->to_x,sd->to_y,0))
+ return 1;
+ memcpy(&sd->walkpath,&wpd,sizeof(wpd));
+
+ clif_walkok(sd);
+ sd->state.change_walk_target=0;
+
+ if((i=calc_next_walk_step(sd))>0){
+ i = i>>2;
+ sd->walktimer=add_timer(gettick()+i,pc_walk,sd->bl.id,0);
+ }
+ clif_movechar(sd);
+
+ return 0;
+}
+
+/*==========================================
+ * pc歩 行要求
+ *------------------------------------------
+ */
+int pc_walktoxy(struct map_session_data *sd,int x,int y)
+{
+
+ nullpo_retr(0, sd);
+
+ sd->to_x=x;
+ sd->to_y=y;
+
+ if(sd->walktimer != -1 && sd->state.change_walk_target==0){
+ // 現在歩いている最中の目的地変更なのでマス目の中心に来た時に
+ // timer関数からpc_walktoxy_subを呼ぶようにする
+ sd->state.change_walk_target=1;
+ } else {
+ pc_walktoxy_sub(sd);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 歩 行停止
+ *------------------------------------------
+ */
+int pc_stop_walking(struct map_session_data *sd,int type)
+{
+ nullpo_retr(0, sd);
+
+ if(sd->walktimer != -1) {
+ delete_timer(sd->walktimer,pc_walk);
+ sd->walktimer=-1;
+ }
+ sd->walkpath.path_len=0;
+ sd->to_x = sd->bl.x;
+ sd->to_y = sd->bl.y;
+ if(type&0x01)
+ clif_fixpos(&sd->bl);
+ if(type&0x02 && battle_config.pc_damage_delay) {
+ unsigned int tick = gettick();
+ int delay = battle_get_dmotion(&sd->bl);
+ if(sd->canmove_tick < tick)
+ sd->canmove_tick = tick + delay;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int pc_movepos(struct map_session_data *sd,int dst_x,int dst_y)
+{
+ int moveblock;
+ int dx,dy,dist;
+
+ struct walkpath_data wpd;
+
+ nullpo_retr(0, sd);
+
+ if(path_search(&wpd,sd->bl.m,sd->bl.x,sd->bl.y,dst_x,dst_y,0))
+ return 1;
+
+ sd->dir = sd->head_dir = map_calc_dir(&sd->bl, dst_x,dst_y);
+
+ dx = dst_x - sd->bl.x;
+ dy = dst_y - sd->bl.y;
+ dist = distance(sd->bl.x,sd->bl.y,dst_x,dst_y);
+
+ moveblock = ( sd->bl.x/BLOCK_SIZE != dst_x/BLOCK_SIZE || sd->bl.y/BLOCK_SIZE != dst_y/BLOCK_SIZE);
+
+ map_foreachinmovearea(clif_pcoutsight,sd->bl.m,sd->bl.x-AREA_SIZE,sd->bl.y-AREA_SIZE,sd->bl.x+AREA_SIZE,sd->bl.y+AREA_SIZE,dx,dy,0,sd);
+
+ if(moveblock) map_delblock(&sd->bl);
+ sd->bl.x = dst_x;
+ sd->bl.y = dst_y;
+ if(moveblock) map_addblock(&sd->bl);
+
+ map_foreachinmovearea(clif_pcinsight,sd->bl.m,sd->bl.x-AREA_SIZE,sd->bl.y-AREA_SIZE,sd->bl.x+AREA_SIZE,sd->bl.y+AREA_SIZE,-dx,-dy,0,sd);
+
+ if(sd->status.party_id>0){ // パーティのHP情報通知検査
+ struct party *p=party_search(sd->status.party_id);
+ if(p!=NULL){
+ int flag=0;
+ map_foreachinmovearea(party_send_hp_check,sd->bl.m,sd->bl.x-AREA_SIZE,sd->bl.y-AREA_SIZE,sd->bl.x+AREA_SIZE,sd->bl.y+AREA_SIZE,-dx,-dy,BL_PC,sd->status.party_id,&flag);
+ if(flag)
+ sd->party_hp=-1;
+ }
+ }
+
+ if(sd->status.option&4) // クローキングの消滅検査
+ skill_check_cloaking(&sd->bl);
+
+ skill_unit_move(&sd->bl,gettick(),dist+7); // スキルユニットの検査
+
+ if(map_getcell(sd->bl.m,sd->bl.x,sd->bl.y)&0x80)
+ npc_touch_areanpc(sd,sd->bl.m,sd->bl.x,sd->bl.y);
+ else
+ sd->areanpc_id=0;
+ return 0;
+}
+
+//
+// 武器戦闘
+//
+/*==========================================
+ * スキルの検索 所有していた場合Lvが返る
+ *------------------------------------------
+ */
+int pc_checkskill(struct map_session_data *sd,int skill_id)
+{
+ if(sd == NULL) return 0;
+ if( skill_id>=10000 ){
+ struct guild *g;
+ if( sd->status.guild_id>0 && (g=guild_search(sd->status.guild_id))!=NULL)
+ return guild_checkskill(g,skill_id);
+ return 0;
+ }
+
+ if(sd->status.skill[skill_id].id == skill_id)
+ return (sd->status.skill[skill_id].lv);
+
+ return 0;
+}
+
+/*==========================================
+ * 武器変更によるスキルの継続チェック
+ * 引数:
+ * struct map_session_data *sd セッションデータ
+ * int nameid 装備品ID
+ * 返り値:
+ * 0 変更なし
+ * -1 スキルを解除
+ *------------------------------------------
+ */
+int pc_checkallowskill(struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+
+ if( sd->sc_data == NULL )
+ return 0;
+
+ if(!(skill_get_weapontype(KN_TWOHANDQUICKEN)&(1<<sd->status.weapon)) && sd->sc_data[SC_TWOHANDQUICKEN].timer!=-1) { // 2HQ
+ skill_status_change_end(&sd->bl,SC_TWOHANDQUICKEN,-1); // 2HQを解除
+ return -1;
+ }
+ if(!(skill_get_weapontype(LK_AURABLADE)&(1<<sd->status.weapon)) && sd->sc_data[SC_AURABLADE].timer!=-1) { /* オーラブレード */
+ skill_status_change_end(&sd->bl,SC_AURABLADE,-1); /* オーラブレードを解除 */
+ return -1;
+ }
+ if(!(skill_get_weapontype(LK_PARRYING)&(1<<sd->status.weapon)) && sd->sc_data[SC_PARRYING].timer!=-1) { /* パリイング */
+ skill_status_change_end(&sd->bl,SC_PARRYING,-1); /* パリイングを解除 */
+ return -1;
+ }
+ if(!(skill_get_weapontype(LK_CONCENTRATION)&(1<<sd->status.weapon)) && sd->sc_data[SC_CONCENTRATION].timer!=-1) { /* コンセントレーション */
+ skill_status_change_end(&sd->bl,SC_CONCENTRATION,-1); /* コンセントレーションを解除 */
+ return -1;
+ }
+ if(!(skill_get_weapontype(CR_SPEARQUICKEN)&(1<<sd->status.weapon)) && sd->sc_data[SC_SPEARSQUICKEN].timer!=-1){ // スピアクィッケン
+ skill_status_change_end(&sd->bl,SC_SPEARSQUICKEN,-1); // スピアクイッケンを解除
+ return -1;
+ }
+ if(!(skill_get_weapontype(BS_ADRENALINE)&(1<<sd->status.weapon)) && sd->sc_data[SC_ADRENALINE].timer!=-1){ // アドレナリンラッシュ
+ skill_status_change_end(&sd->bl,SC_ADRENALINE,-1); // アドレナリンラッシュを解除
+ return -1;
+ }
+
+ if(sd->status.shield <= 0) {
+ if(sd->sc_data[SC_AUTOGUARD].timer!=-1){ // オートガード
+ skill_status_change_end(&sd->bl,SC_AUTOGUARD,-1);
+ return -1;
+ }
+ if(sd->sc_data[SC_DEFENDER].timer!=-1){ // ディフェンダー
+ skill_status_change_end(&sd->bl,SC_DEFENDER,-1);
+ return -1;
+ }
+ if(sd->sc_data[SC_REFLECTSHIELD].timer!=-1){ //リフレクトシールド
+ skill_status_change_end(&sd->bl,SC_REFLECTSHIELD,-1);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 装 備品のチェック
+ *------------------------------------------
+ */
+int pc_checkequip(struct map_session_data *sd,int pos)
+{
+ int i;
+
+ nullpo_retr(-1, sd);
+
+ for(i=0;i<11;i++){
+ if(pos & equip_pos[i])
+ return sd->equip_index[i];
+ }
+
+ return -1;
+}
+
+/*==========================================
+ * 転生職や養子職の元の職業を返す
+ *------------------------------------------
+ */
+struct pc_base_job pc_calc_base_job(int b_class)
+{
+ struct pc_base_job bj;
+ //転生や養子の場合の元の職業を算出する
+ if(b_class < MAX_PC_CLASS){ //通常
+ bj.job = b_class;
+ bj.upper = 0;
+ }else if(b_class >= 4001 && b_class < 4023){ //転生職
+ bj.job = b_class - 4001;
+ bj.upper = 1;
+ }else if(b_class == 23 + 4023 -1){ //養子スパノビ
+ bj.job = b_class - (4023 - 1);
+ bj.upper = 2;
+ }else{ //養子スパノビ以外の養子
+ bj.job = b_class - 4023;
+ bj.upper = 2;
+ }
+
+ if(battle_config.enable_upper_class==0){ //confで無効になっていたらupper=0
+ bj.upper = 0;
+ }
+
+ if(bj.job == 0){
+ bj.type = 0;
+ }else if(bj.job < 7){
+ bj.type = 1;
+ }else{
+ bj.type = 2;
+ }
+
+ return bj;
+}
+
+/*==========================================
+ * PCの攻撃 (timer関数)
+ *------------------------------------------
+ */
+int pc_attack_timer(int tid,unsigned int tick,int id,int data)
+{
+ struct map_session_data *sd;
+ struct block_list *bl;
+ struct status_change *sc_data;
+ short *opt;
+ int dist,skill,range;
+
+ sd=map_id2sd(id);
+ if(sd == NULL)
+ return 0;
+ if(sd->attacktimer != tid){
+ if(battle_config.error_log)
+ printf("pc_attack_timer %d != %d\n",sd->attacktimer,tid);
+ return 0;
+ }
+ sd->attacktimer=-1;
+
+ if(sd->bl.prev == NULL)
+ return 0;
+
+ bl=map_id2bl(sd->attacktarget);
+ if(bl==NULL || bl->prev == NULL)
+ return 0;
+
+ if(bl->type == BL_PC && pc_isdead((struct map_session_data *)bl))
+ return 0;
+
+ // 同じmapでないなら攻撃しない
+ // PCが死んでても攻撃しない
+ if(sd->bl.m != bl->m || pc_isdead(sd))
+ return 0;
+
+ if( sd->opt1>0 || sd->status.option&2 || sd->status.option&16388) // 異常などで攻撃できない
+ return 0;
+
+ if(sd->sc_data[SC_AUTOCOUNTER].timer != -1)
+ return 0;
+ if(sd->sc_data[SC_BLADESTOP].timer != -1)
+ return 0;
+
+ if((opt = battle_get_option(bl)) != NULL && *opt&0x46)
+ return 0;
+ if(((sc_data = battle_get_sc_data(bl)) != NULL && sc_data[SC_TRICKDEAD].timer != -1) ||
+ ((sc_data = battle_get_sc_data(bl)) != NULL && sc_data[SC_BASILICA].timer != -1 ))
+ return 0;
+
+ if(sd->skilltimer != -1 && pc_checkskill(sd,SA_FREECAST) <= 0)
+ return 0;
+
+ if(!battle_config.sdelay_attack_enable && pc_checkskill(sd,SA_FREECAST) <= 0) {
+ if(DIFF_TICK(tick , sd->canact_tick) < 0) {
+ clif_skill_fail(sd,1,4,0);
+ return 0;
+ }
+ }
+
+ dist = distance(sd->bl.x,sd->bl.y,bl->x,bl->y);
+ range = sd->attackrange;
+ if(sd->status.weapon != 11) range++;
+ if( dist > range ){ // 届 かないので移動
+ if(pc_can_reach(sd,bl->x,bl->y))
+ clif_movetoattack(sd,bl);
+ return 0;
+ }
+
+ if(dist <= range && !battle_check_range(&sd->bl,bl,range) ) {
+ if(pc_can_reach(sd,bl->x,bl->y) && sd->canmove_tick < tick && (sd->sc_data[SC_ANKLE].timer == -1 || sd->sc_data[SC_SPIDERWEB].timer == -1))
+ pc_walktoxy(sd,bl->x,bl->y);
+ sd->attackabletime = tick + (sd->aspd<<1);
+ }
+ else {
+ if(battle_config.pc_attack_direction_change)
+ sd->dir=sd->head_dir=map_calc_dir(&sd->bl, bl->x,bl->y ); // 向き設定
+
+ if(sd->walktimer != -1)
+ pc_stop_walking(sd,1);
+
+ if(sd->sc_data[SC_COMBO].timer == -1) {
+ map_freeblock_lock();
+ pc_stop_walking(sd,0);
+ sd->attacktarget_lv = battle_weapon_attack(&sd->bl,bl,tick,0);
+ if(!(battle_config.pc_cloak_check_type&2) && sd->sc_data[SC_CLOAKING].timer != -1)
+ skill_status_change_end(&sd->bl,SC_CLOAKING,-1);
+ if(sd->status.pet_id > 0 && sd->pd && sd->petDB && battle_config.pet_attack_support)
+ pet_target_check(sd,bl,0);
+ map_freeblock_unlock();
+ if(sd->skilltimer != -1 && (skill = pc_checkskill(sd,SA_FREECAST)) > 0 ) // フリーキャスト
+ sd->attackabletime = tick + ((sd->aspd<<1)*(150 - skill*5)/100);
+ else
+ sd->attackabletime = tick + (sd->aspd<<1);
+ }
+ else if(sd->attackabletime <= tick) {
+ if(sd->skilltimer != -1 && (skill = pc_checkskill(sd,SA_FREECAST)) > 0 ) // フリーキャスト
+ sd->attackabletime = tick + ((sd->aspd<<1)*(150 - skill*5)/100);
+ else
+ sd->attackabletime = tick + (sd->aspd<<1);
+ }
+ if(sd->attackabletime <= tick) sd->attackabletime = tick + (battle_config.max_aspd<<1);
+ }
+
+ if(sd->state.attack_continue) {
+ sd->attacktimer=add_timer(sd->attackabletime,pc_attack_timer,sd->bl.id,0);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 攻撃要求
+ * typeが1なら継続攻撃
+ *------------------------------------------
+ */
+int pc_attack(struct map_session_data *sd,int target_id,int type)
+{
+ struct block_list *bl;
+ int d;
+
+ nullpo_retr(0, sd);
+
+ bl=map_id2bl(target_id);
+ if(bl==NULL)
+ return 1;
+
+ if(bl->type==BL_NPC) { // monster npcs [Valaris]
+ npc_click(sd,RFIFOL(sd->fd,2));
+ return 0;
+ }
+
+ if(!battle_check_target(&sd->bl,bl,BCT_ENEMY))
+ return 1;
+ if(sd->attacktimer != -1)
+ pc_stopattack(sd);
+ sd->attacktarget=target_id;
+ sd->state.attack_continue=type;
+
+ d=DIFF_TICK(sd->attackabletime,gettick());
+ if(d>0 && d<2000){ // 攻撃delay中
+ sd->attacktimer=add_timer(sd->attackabletime,pc_attack_timer,sd->bl.id,0);
+ } else {
+ // 本来timer関数なので引数を合わせる
+ pc_attack_timer(-1,gettick(),sd->bl.id,0);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 継続攻撃停止
+ *------------------------------------------
+ */
+int pc_stopattack(struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+
+ if(sd->attacktimer != -1) {
+ delete_timer(sd->attacktimer,pc_attack_timer);
+ sd->attacktimer=-1;
+ }
+ sd->attacktarget=0;
+ sd->state.attack_continue=0;
+
+ return 0;
+}
+
+int pc_follow_timer(int tid,unsigned int tick,int id,int data)
+{
+ struct map_session_data *sd, *bl;
+
+ sd=map_id2sd(id);
+ if(sd == NULL || sd->followtimer != tid)
+ return 0;
+
+ sd->followtimer=-1;
+
+ do {
+ if(sd->bl.prev == NULL)
+ break;
+
+ bl=(struct map_session_data *) map_id2bl(sd->followtarget);
+
+ if(bl==NULL)
+ return 0;
+
+ if(bl->bl.prev == NULL)
+ break;
+
+ if(bl->bl.type == BL_PC && pc_isdead((struct map_session_data *)bl))
+ return 0;
+
+ if (sd->skilltimer == -1 && sd->attacktimer == -1 && sd->walktimer == -1) {
+ if((sd->bl.m == bl->bl.m) && pc_can_reach(sd,bl->bl.x,bl->bl.y)) {
+ if (distance(sd->bl.x,sd->bl.y,bl->bl.x,bl->bl.y) > 5)
+ pc_walktoxy(sd,bl->bl.x,bl->bl.y);
+ } else
+ pc_setpos((struct map_session_data*)sd, bl->mapname, bl->bl.x, bl->bl.y, 3);
+ }
+ } while (0);
+
+ sd->followtimer=add_timer(tick + sd->aspd,pc_follow_timer,sd->bl.id,0);
+
+ return 0;
+}
+
+int pc_follow(struct map_session_data *sd,int target_id)
+{
+ struct block_list *bl;
+
+ bl=map_id2bl(target_id);
+ if(bl==NULL)
+ return 1;
+ sd->followtarget=target_id;
+ if(sd->followtimer != -1) {
+ delete_timer(sd->followtimer,pc_follow_timer);
+ sd->followtimer = -1;
+ }
+
+ pc_follow_timer(-1,gettick(),sd->bl.id,0);
+
+ return 0;
+}
+
+int pc_checkbaselevelup(struct map_session_data *sd)
+{
+ int next = pc_nextbaseexp(sd);
+
+ nullpo_retr(0, sd);
+
+ if(sd->status.base_exp >= next && next > 0){
+ struct pc_base_job s_class = pc_calc_base_job(sd->status.class);
+
+ // base側レベルアップ処理
+ sd->status.base_exp -= next;
+
+ sd->status.base_level ++;
+ sd->status.status_point += (sd->status.base_level+14) / 5 ;
+ clif_updatestatus(sd,SP_STATUSPOINT);
+ clif_updatestatus(sd,SP_BASELEVEL);
+ clif_updatestatus(sd,SP_NEXTBASEEXP);
+ pc_calcstatus(sd,0);
+ pc_heal(sd,sd->status.max_hp,sd->status.max_sp);
+
+ //スパノビはキリエ、イムポ、マニピ、グロ、サフラLv1がかかる
+ if(s_class.job == 23){
+ skill_status_change_start(&sd->bl,SkillStatusChangeTable[PR_KYRIE],1,0,0,0,skill_get_time(PR_KYRIE,1),0 );
+ skill_status_change_start(&sd->bl,SkillStatusChangeTable[PR_IMPOSITIO],1,0,0,0,skill_get_time(PR_IMPOSITIO,1),0 );
+ skill_status_change_start(&sd->bl,SkillStatusChangeTable[PR_MAGNIFICAT],1,0,0,0,skill_get_time(PR_MAGNIFICAT,1),0 );
+ skill_status_change_start(&sd->bl,SkillStatusChangeTable[PR_GLORIA],1,0,0,0,skill_get_time(PR_GLORIA,1),0 );
+ skill_status_change_start(&sd->bl,SkillStatusChangeTable[PR_SUFFRAGIUM],1,0,0,0,skill_get_time(PR_SUFFRAGIUM,1),0 );
+ }
+
+ clif_misceffect(&sd->bl,0);
+ //レベルアップしたのでパーティー情報を更新する
+ //(公平範囲チェック)
+ party_send_movemap(sd);
+ return 1;
+ }
+
+ return 0;
+}
+
+int pc_checkjoblevelup(struct map_session_data *sd)
+{
+ int next = pc_nextjobexp(sd);
+
+ nullpo_retr(0, sd);
+
+ if(sd->status.job_exp >= next && next > 0){
+ // job側レベルアップ処理
+ sd->status.job_exp -= next;
+ sd->status.job_level ++;
+ clif_updatestatus(sd,SP_JOBLEVEL);
+ clif_updatestatus(sd,SP_NEXTJOBEXP);
+ sd->status.skill_point ++;
+ clif_updatestatus(sd,SP_SKILLPOINT);
+ pc_calcstatus(sd,0);
+
+ clif_misceffect(&sd->bl,1);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 経験値取得
+ *------------------------------------------
+ */
+int pc_gainexp(struct map_session_data *sd,int base_exp,int job_exp)
+{
+ char output[256];
+ nullpo_retr(0, sd);
+
+ if(sd->bl.prev == NULL || pc_isdead(sd))
+ return 0;
+
+ if((battle_config.pvp_exp == 0) && map[sd->bl.m].flag.pvp) // [MouseJstr]
+ return 0; // no exp on pvp maps
+
+ if(sd->sc_data[SC_RICHMANKIM].timer != -1) { // added bounds checking [Vaalris]
+ base_exp += base_exp*(25 + sd->sc_data[SC_RICHMANKIM].val1*25)/100;
+ job_exp += job_exp*(25 + sd->sc_data[SC_RICHMANKIM].val1*25)/100;
+ }
+
+ if(sd->status.guild_id>0){ // ギルドに上納
+ base_exp-=guild_payexp(sd,base_exp);
+ if(base_exp < 0)
+ base_exp = 0;
+ }
+
+ if(!battle_config.multi_level_up && pc_nextbaseafter(sd) && sd->status.base_exp+base_exp >= pc_nextbaseafter(sd)) {
+ base_exp = pc_nextbaseafter(sd) - sd->status.base_exp;
+ if (base_exp < 0)
+ base_exp = 0;
+ }
+
+ sd->status.base_exp += base_exp;
+ if(sd->status.base_exp < 0)
+ sd->status.base_exp = 0;
+
+ while(pc_checkbaselevelup(sd)) ;
+
+ clif_updatestatus(sd,SP_BASEEXP);
+ if(!battle_config.multi_level_up && pc_nextjobafter(sd) && sd->status.job_exp+job_exp >= pc_nextjobafter(sd)) {
+ job_exp = pc_nextjobafter(sd) - sd->status.job_exp;
+ if (job_exp < 0)
+ job_exp = 0;
+ }
+
+ sd->status.job_exp += job_exp;
+ if(sd->status.job_exp < 0)
+ sd->status.job_exp = 0;
+
+ while(pc_checkjoblevelup(sd)) ;
+
+ clif_updatestatus(sd,SP_JOBEXP);
+
+ if(battle_config.disp_experience){
+ sprintf(output,
+ "Experienced Gained Base:%d Job:%d",base_exp,job_exp);
+ clif_disp_onlyself(sd,output,strlen(output));
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * base level側必要経験値計算
+ *------------------------------------------
+ */
+int pc_nextbaseexp(struct map_session_data *sd)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if(sd->status.base_level>=MAX_LEVEL || sd->status.base_level<=0)
+ return 0;
+
+ if(sd->status.class==0) i=0;
+ else if(sd->status.class<=6) i=1;
+ else if(sd->status.class<=22) i=2;
+ else if(sd->status.class==23) i=3;
+ else if(sd->status.class==4001) i=4;
+ else if(sd->status.class<=4007) i=5;
+ else i=6;
+
+ return exp_table[i][sd->status.base_level-1];
+}
+
+/*==========================================
+ * job level側必要経験値計算
+ *------------------------------------------
+ */
+int pc_nextjobexp(struct map_session_data *sd)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if(sd->status.job_level>=MAX_LEVEL || sd->status.job_level<=0)
+ return 0;
+
+ if(sd->status.class==0) i=7;
+ else if(sd->status.class<=6) i=8;
+ else if(sd->status.class<=22) i=9;
+ else if(sd->status.class==23) i=10;
+ else if(sd->status.class==4001) i=11;
+ else if(sd->status.class<=4007) i=12;
+ else i=13;
+
+ return exp_table[i][sd->status.job_level-1];
+}
+
+/*==========================================
+ * base level after next [Valaris]
+ *------------------------------------------
+ */
+int pc_nextbaseafter(struct map_session_data *sd)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if(sd->status.base_level>=MAX_LEVEL || sd->status.base_level<=0)
+ return 0;
+
+ if(sd->status.class==0) i=0;
+ else if(sd->status.class<=6) i=1;
+ else if(sd->status.class<=22) i=2;
+ else if(sd->status.class==23) i=3;
+ else if(sd->status.class==4001) i=4;
+ else if(sd->status.class<=4007) i=5;
+ else i=6;
+
+ return exp_table[i][sd->status.base_level];
+}
+
+/*==========================================
+ * job level after next [Valaris]
+ *------------------------------------------
+ */
+int pc_nextjobafter(struct map_session_data *sd)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if(sd->status.job_level>=MAX_LEVEL || sd->status.job_level<=0)
+ return 0;
+
+ if(sd->status.class==0) i=7;
+ else if(sd->status.class<=6) i=8;
+ else if(sd->status.class<=22) i=9;
+ else if(sd->status.class==23) i=10;
+ else if(sd->status.class==4001) i=11;
+ else if(sd->status.class<=4007) i=12;
+ else i=13;
+
+ return exp_table[i][sd->status.job_level];
+}
+/*==========================================
+
+ * 必要ステータスポイント計算
+ *------------------------------------------
+ */
+int pc_need_status_point(struct map_session_data *sd,int type)
+{
+ int val;
+
+ nullpo_retr(-1, sd);
+
+ if(type<SP_STR || type>SP_LUK)
+ return -1;
+ val =
+ type==SP_STR ? sd->status.str :
+ type==SP_AGI ? sd->status.agi :
+ type==SP_VIT ? sd->status.vit :
+ type==SP_INT ? sd->status.int_:
+ type==SP_DEX ? sd->status.dex : sd->status.luk;
+
+ return (val+9)/10+1;
+}
+
+/*==========================================
+ * 能力値成長
+ *------------------------------------------
+ */
+int pc_statusup(struct map_session_data *sd,int type)
+{
+ int need,val = 0;
+
+ nullpo_retr(0, sd);
+
+ need=pc_need_status_point(sd,type);
+ if(type<SP_STR || type>SP_LUK || need<0 || need>sd->status.status_point){
+ clif_statusupack(sd,type,0,0);
+ return 1;
+ }
+ switch(type){
+ case SP_STR:
+ if(sd->status.str >= battle_config.max_parameter) {
+ clif_statusupack(sd,type,0,0);
+ return 1;
+ }
+ val= ++sd->status.str;
+ break;
+ case SP_AGI:
+ if(sd->status.agi >= battle_config.max_parameter) {
+ clif_statusupack(sd,type,0,0);
+ return 1;
+ }
+ val= ++sd->status.agi;
+ break;
+ case SP_VIT:
+ if(sd->status.vit >= battle_config.max_parameter) {
+ clif_statusupack(sd,type,0,0);
+ return 1;
+ }
+ val= ++sd->status.vit;
+ break;
+ case SP_INT:
+ if(sd->status.int_ >= battle_config.max_parameter) {
+ clif_statusupack(sd,type,0,0);
+ return 1;
+ }
+ val= ++sd->status.int_;
+ break;
+ case SP_DEX:
+ if(sd->status.dex >= battle_config.max_parameter) {
+ clif_statusupack(sd,type,0,0);
+ return 1;
+ }
+ val= ++sd->status.dex;
+ break;
+ case SP_LUK:
+ if(sd->status.luk >= battle_config.max_parameter) {
+ clif_statusupack(sd,type,0,0);
+ return 1;
+ }
+ val= ++sd->status.luk;
+ break;
+ }
+ sd->status.status_point-=need;
+ if(need!=pc_need_status_point(sd,type)){
+ clif_updatestatus(sd,type-SP_STR+SP_USTR);
+ }
+ clif_updatestatus(sd,SP_STATUSPOINT);
+ clif_updatestatus(sd,type);
+ pc_calcstatus(sd,0);
+ clif_statusupack(sd,type,1,val);
+
+ return 0;
+}
+
+/*==========================================
+ * 能力値成長
+ *------------------------------------------
+ */
+int pc_statusup2(struct map_session_data *sd,int type,int val)
+{
+ nullpo_retr(0, sd);
+
+ if(type<SP_STR || type>SP_LUK){
+ clif_statusupack(sd,type,0,0);
+ return 1;
+ }
+ switch(type){
+ case SP_STR:
+ if(sd->status.str + val >= battle_config.max_parameter)
+ val = battle_config.max_parameter;
+ else if(sd->status.str + val < 1)
+ val = 1;
+ else
+ val += sd->status.str;
+ sd->status.str = val;
+ break;
+ case SP_AGI:
+ if(sd->status.agi + val >= battle_config.max_parameter)
+ val = battle_config.max_parameter;
+ else if(sd->status.agi + val < 1)
+ val = 1;
+ else
+ val += sd->status.agi;
+ sd->status.agi = val;
+ break;
+ case SP_VIT:
+ if(sd->status.vit + val >= battle_config.max_parameter)
+ val = battle_config.max_parameter;
+ else if(sd->status.vit + val < 1)
+ val = 1;
+ else
+ val += sd->status.vit;
+ sd->status.vit = val;
+ break;
+ case SP_INT:
+ if(sd->status.int_ + val >= battle_config.max_parameter)
+ val = battle_config.max_parameter;
+ else if(sd->status.int_ + val < 1)
+ val = 1;
+ else
+ val += sd->status.int_;
+ sd->status.int_ = val;
+ break;
+ case SP_DEX:
+ if(sd->status.dex + val >= battle_config.max_parameter)
+ val = battle_config.max_parameter;
+ else if(sd->status.dex + val < 1)
+ val = 1;
+ else
+ val += sd->status.dex;
+ sd->status.dex = val;
+ break;
+ case SP_LUK:
+ if(sd->status.luk + val >= battle_config.max_parameter)
+ val = battle_config.max_parameter;
+ else if(sd->status.luk + val < 1)
+ val = 1;
+ else
+ val = sd->status.luk + val;
+ sd->status.luk = val;
+ break;
+ }
+ clif_updatestatus(sd,type-SP_STR+SP_USTR);
+ clif_updatestatus(sd,type);
+ pc_calcstatus(sd,0);
+ clif_statusupack(sd,type,1,val);
+
+ return 0;
+}
+
+/*==========================================
+ * スキルポイント割り振り
+ *------------------------------------------
+ */
+int pc_skillup(struct map_session_data *sd,int skill_num)
+{
+ nullpo_retr(0, sd);
+
+ if( skill_num>=10000 ){
+ guild_skillup(sd,skill_num,0);
+ return 0;
+ }
+
+ if( sd->status.skill_point>0 &&
+ sd->status.skill[skill_num].id!=0 &&
+ sd->status.skill[skill_num].lv < skill_get_max(skill_num) )
+ {
+ sd->status.skill[skill_num].lv++;
+ sd->status.skill_point--;
+ pc_calcstatus(sd,0);
+ clif_skillup(sd,skill_num);
+ clif_updatestatus(sd,SP_SKILLPOINT);
+ clif_skillinfoblock(sd);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * /allskill
+ *------------------------------------------
+ */
+int pc_allskillup(struct map_session_data *sd)
+{
+ int i,id;
+ int c=0, s=0;
+ //転生や養子の場合の元の職業を算出する
+ struct pc_base_job s_class;
+
+ nullpo_retr(0, sd);
+
+ s_class = pc_calc_base_job(sd->status.class);
+ c = s_class.job;
+ s = (s_class.upper==1) ? 1 : 0 ; //転生以外は通常のスキル?
+
+ for(i=0;i<MAX_SKILL;i++){
+ sd->status.skill[i].id=0;
+ if (sd->status.skill[i].flag && sd->status.skill[i].flag != 13){ // cardスキルなら、
+ sd->status.skill[i].lv=(sd->status.skill[i].flag==1)?0:sd->status.skill[i].flag-2; // 本当のlvに
+ sd->status.skill[i].flag=0; // flagは0にしておく
+ }
+ }
+
+ if (battle_config.gm_allskill > 0 && pc_isGM(sd) >= battle_config.gm_allskill){
+ // 全てのスキル
+ for(i=1;i<158;i++)
+ sd->status.skill[i].lv=skill_get_max(i);
+ for(i=210;i<291;i++)
+ sd->status.skill[i].lv=skill_get_max(i);
+ for(i=304;i<MAX_SKILL;i++){
+ if(i==331) continue;
+ sd->status.skill[i].lv=skill_get_max(i);
+ }
+ }
+ else {
+ for(i=0;(id=skill_tree[s][c][i].id)>0;i++){
+ if(sd->status.skill[id].id==0 && (!(skill_get_inf2(id)&0x01) || battle_config.quest_skill_learn) )
+ sd->status.skill[id].lv=skill_get_max(id);
+ }
+ }
+ pc_calcstatus(sd,0);
+
+ return 0;
+}
+
+/*==========================================
+ * /resetlvl
+ *------------------------------------------
+ */
+int pc_resetlvl(struct map_session_data* sd,int type)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ for(i=1;i<MAX_SKILL;i++){
+ sd->status.skill[i].lv = 0;
+ }
+
+ if(type == 1){
+ sd->status.skill_point=0;
+ sd->status.base_level=1;
+ sd->status.job_level=1;
+ sd->status.base_exp=sd->status.base_exp=0;
+ sd->status.job_exp=sd->status.job_exp=0;
+ if(sd->status.option !=0)
+ sd->status.option = 0;
+
+ sd->status.str=1;
+ sd->status.agi=1;
+ sd->status.vit=1;
+ sd->status.int_=1;
+ sd->status.dex=1;
+ sd->status.luk=1;
+ if(sd->status.class == 4001)
+ sd->status.status_point=88;
+ }
+
+ if(type == 2){
+ sd->status.skill_point=0;
+ sd->status.base_level=1;
+ sd->status.job_level=1;
+ sd->status.base_exp=0;
+ sd->status.job_exp=0;
+ }
+ if(type == 3){
+ sd->status.base_level=1;
+ sd->status.base_exp=0;
+ }
+ if(type == 4){
+ sd->status.job_level=1;
+ sd->status.job_exp=0;
+ }
+
+ clif_updatestatus(sd,SP_STATUSPOINT);
+ clif_updatestatus(sd,SP_STR);
+ clif_updatestatus(sd,SP_AGI);
+ clif_updatestatus(sd,SP_VIT);
+ clif_updatestatus(sd,SP_INT);
+ clif_updatestatus(sd,SP_DEX);
+ clif_updatestatus(sd,SP_LUK);
+ clif_updatestatus(sd,SP_BASELEVEL);
+ clif_updatestatus(sd,SP_JOBLEVEL);
+ clif_updatestatus(sd,SP_STATUSPOINT);
+ clif_updatestatus(sd,SP_NEXTBASEEXP);
+ clif_updatestatus(sd,SP_NEXTJOBEXP);
+ clif_updatestatus(sd,SP_SKILLPOINT);
+
+ clif_updatestatus(sd,SP_USTR); // Updates needed stat points - Valaris
+ clif_updatestatus(sd,SP_UAGI);
+ clif_updatestatus(sd,SP_UVIT);
+ clif_updatestatus(sd,SP_UINT);
+ clif_updatestatus(sd,SP_UDEX);
+ clif_updatestatus(sd,SP_ULUK); // End Addition
+
+ for(i=0;i<11;i++) { // unequip items that can't be equipped by base 1 [Valaris]
+ if(sd->equip_index[i] >= 0)
+ if(!pc_isequip(sd,sd->equip_index[i]))
+ pc_unequipitem(sd,sd->equip_index[i],1);
+ }
+
+ clif_skillinfoblock(sd);
+ pc_calcstatus(sd,0);
+
+ return 0;
+}
+/*==========================================
+ * /resetstate
+ *------------------------------------------
+ */
+int pc_resetstate(struct map_session_data* sd)
+{
+ #define sumsp(a) ((a)*((a-2)/10+2) - 5*((a-2)/10)*((a-2)/10) - 6*((a-2)/10) -2)
+// int add=0; // Removed by Dexity
+
+ nullpo_retr(0, sd);
+
+// New statpoint table used here - Dexity
+ sd->status.status_point = atoi (statp[sd->status.base_level - 1]);
+ if(sd->status.class >= 4001 && sd->status.class <= 4024)
+ sd->status.status_point+=40;
+// End addition
+
+// Removed by Dexity - old count
+// add += sumsp(sd->status.str);
+// add += sumsp(sd->status.agi);
+// add += sumsp(sd->status.vit);
+// add += sumsp(sd->status.int_);
+// add += sumsp(sd->status.dex);
+// add += sumsp(sd->status.luk);
+// sd->status.status_point+=add;
+
+ clif_updatestatus(sd,SP_STATUSPOINT);
+
+ sd->status.str=1;
+ sd->status.agi=1;
+ sd->status.vit=1;
+ sd->status.int_=1;
+ sd->status.dex=1;
+ sd->status.luk=1;
+
+ clif_updatestatus(sd,SP_STR);
+ clif_updatestatus(sd,SP_AGI);
+ clif_updatestatus(sd,SP_VIT);
+ clif_updatestatus(sd,SP_INT);
+ clif_updatestatus(sd,SP_DEX);
+ clif_updatestatus(sd,SP_LUK);
+
+ clif_updatestatus(sd,SP_USTR); // Updates needed stat points - Valaris
+ clif_updatestatus(sd,SP_UAGI);
+ clif_updatestatus(sd,SP_UVIT);
+ clif_updatestatus(sd,SP_UINT);
+ clif_updatestatus(sd,SP_UDEX);
+ clif_updatestatus(sd,SP_ULUK); // End Addition
+
+ pc_calcstatus(sd,0);
+
+ return 0;
+}
+
+/*==========================================
+ * /resetskill
+ *------------------------------------------
+ */
+int pc_resetskill(struct map_session_data* sd)
+{
+ int i,skill;
+
+ nullpo_retr(0, sd);
+
+ for(i=1;i<MAX_SKILL;i++){
+ if( (skill = pc_checkskill(sd,i)) > 0) {
+ if(!(skill_get_inf2(i)&0x01) || battle_config.quest_skill_learn) {
+ if(!sd->status.skill[i].flag)
+ sd->status.skill_point += skill;
+ else if(sd->status.skill[i].flag > 2 && sd->status.skill[i].flag != 13) {
+ sd->status.skill_point += (sd->status.skill[i].flag - 2);
+ }
+ sd->status.skill[i].lv = 0;
+ }
+ else if(battle_config.quest_skill_reset)
+ sd->status.skill[i].lv = 0;
+ sd->status.skill[i].flag = 0;
+ }
+ else
+ sd->status.skill[i].lv = 0;
+ }
+ clif_updatestatus(sd,SP_SKILLPOINT);
+ clif_skillinfoblock(sd);
+ pc_calcstatus(sd,0);
+
+ return 0;
+}
+
+/*==========================================
+ * pcにダメージを与える
+ *------------------------------------------
+ */
+int pc_damage(struct block_list *src,struct map_session_data *sd,int damage)
+{
+ int i=0,j=0;
+ struct pc_base_job s_class;
+
+ nullpo_retr(0, sd);
+
+ //転生や養子の場合の元の職業を算出する
+ s_class = pc_calc_base_job(sd->status.class);
+ // 既に死んでいたら無効
+ if(pc_isdead(sd))
+ return 0;
+ // 座ってたら立ち上がる
+ if(pc_issit(sd)) {
+ pc_setstand(sd);
+ skill_gangsterparadise(sd,0);
+ }
+
+ // 歩 いていたら足を止める
+ if(sd->sc_data[SC_ENDURE].timer == -1 && !sd->special_state.infinite_endure)
+ pc_stop_walking(sd,3);
+ // 演奏/ダンスの中断
+ if(damage > sd->status.max_hp>>2)
+ skill_stop_dancing(&sd->bl,0);
+
+ sd->status.hp-=damage;
+ if(sd->status.pet_id > 0 && sd->pd && sd->petDB && battle_config.pet_damage_support)
+ pet_target_check(sd,src,1);
+
+ if (sd->sc_data[SC_TRICKDEAD].timer != -1)
+ skill_status_change_end(&sd->bl, SC_TRICKDEAD, -1);
+ if(sd->status.option&2)
+ skill_status_change_end(&sd->bl, SC_HIDING, -1);
+ if(sd->status.option&4)
+ skill_status_change_end(&sd->bl, SC_CLOAKING, -1);
+ if(sd->status.option&16386)
+ skill_status_change_end(&sd->bl, SC_CHASEWALK, -1);
+
+ if(sd->status.hp>0){
+ // まだ生きているならHP更新
+ clif_updatestatus(sd,SP_HP);
+
+ if(sd->status.hp<sd->status.max_hp>>2 && pc_checkskill(sd,SM_AUTOBERSERK)>0 &&
+ (sd->sc_data[SC_PROVOKE].timer==-1 || sd->sc_data[SC_PROVOKE].val2==0 ))
+ // オートバーサーク発動
+ skill_status_change_start(&sd->bl,SC_PROVOKE,10,1,0,0,0,0);
+
+ sd->canlog_tick = gettick();
+
+ if(sd->status.party_id>0) { // on-the-fly party hp updates [Valaris]
+ struct party *p=party_search(sd->status.party_id);
+ if(p!=NULL) clif_party_hp(p,sd);
+ } // end addition [Valaris]
+
+ return 0;
+ }
+ sd->status.hp = 0;
+ pc_setdead(sd);
+ if(sd->vender_id)
+ vending_closevending(sd);
+
+ if(sd->status.pet_id > 0 && sd->pd) {
+ if(sd->petDB) {
+ sd->pet.intimate -= sd->petDB->die;
+ if(sd->pet.intimate < 0)
+ sd->pet.intimate = 0;
+ clif_send_petdata(sd,1,sd->pet.intimate);
+ }
+ }
+
+ pc_stop_walking(sd,0);
+ skill_castcancel(&sd->bl,0); // 詠唱の中止
+ clif_clearchar_area(&sd->bl,1);
+ skill_unit_out_all(&sd->bl,gettick(),1);
+ if(sd->sc_data[SC_BLADESTOP].timer!=-1)//白刃は事前に解除
+ skill_status_change_end(&sd->bl,SC_BLADESTOP,-1);
+ pc_setglobalreg(sd,"PC_DIE_COUNTER",++sd->die_counter); //死にカウンター書き込み
+ skill_status_change_clear(&sd->bl,0); // ステータス異常を解除する
+ clif_updatestatus(sd,SP_HP);
+ pc_calcstatus(sd,0);
+
+ for(i=0;i<5;i++)
+ if(sd->dev.val1[i]){
+ skill_status_change_end(&map_id2sd(sd->dev.val1[i])->bl,SC_DEVOTION,-1);
+ sd->dev.val1[i] = sd->dev.val2[i]=0;
+ }
+
+ if(battle_config.death_penalty_type>0) { // changed penalty options, added death by player if pk_mode [Valaris]
+ if(sd->status.class != 0 && !map[sd->bl.m].flag.nopenalty && !map[sd->bl.m].flag.gvg){ // only novices will recieve no penalty
+ if(battle_config.death_penalty_type==1 && battle_config.death_penalty_base > 0)
+ sd->status.base_exp -= (double)pc_nextbaseexp(sd) * (double)battle_config.death_penalty_base/10000;
+ if(battle_config.pk_mode && src && src->type==BL_PC)
+ sd->status.base_exp -= (double)pc_nextbaseexp(sd) * (double)battle_config.death_penalty_base/10000;
+ else if(battle_config.death_penalty_type==2 && battle_config.death_penalty_base > 0) {
+ if(pc_nextbaseexp(sd) > 0)
+ sd->status.base_exp -= (double)sd->status.base_exp * (double)battle_config.death_penalty_base/10000;
+ if(battle_config.pk_mode && src && src->type==BL_PC)
+ sd->status.base_exp -= (double)sd->status.base_exp * (double)battle_config.death_penalty_base/10000;
+ }
+ if(sd->status.base_exp < 0)
+ sd->status.base_exp = 0;
+ clif_updatestatus(sd,SP_BASEEXP);
+
+ if(battle_config.death_penalty_type==1 && battle_config.death_penalty_job > 0)
+ sd->status.job_exp -= (double)pc_nextjobexp(sd) * (double)battle_config.death_penalty_job/10000;
+ if(battle_config.pk_mode && src && src->type==BL_PC)
+ sd->status.job_exp -= (double)pc_nextjobexp(sd) * (double)battle_config.death_penalty_job/10000;
+ else if(battle_config.death_penalty_type==2 && battle_config.death_penalty_job > 0) {
+ if(pc_nextjobexp(sd) > 0)
+ sd->status.job_exp -= (double)sd->status.job_exp * (double)battle_config.death_penalty_job/10000;
+ if(battle_config.pk_mode && src && src->type==BL_PC)
+ sd->status.job_exp -= (double)sd->status.job_exp * (double)battle_config.death_penalty_job/10000;
+ }
+ if(sd->status.job_exp < 0)
+ sd->status.job_exp = 0;
+ clif_updatestatus(sd,SP_JOBEXP);
+ }
+ }
+ //ナイトメアモードアイテムドロップ
+ if(map[sd->bl.m].flag.pvp_nightmaredrop){ // Moved this outside so it works when PVP isnt enabled and during pk mode [Ancyker]
+ for(j=0;j<MAX_DROP_PER_MAP;j++){
+ int id = map[sd->bl.m].drop_list[j].drop_id;
+ int type = map[sd->bl.m].drop_list[j].drop_type;
+ int per = map[sd->bl.m].drop_list[j].drop_per;
+ if(id == 0)
+ continue;
+ if(id == -1){//ランダムドロップ
+ int eq_num=0,eq_n[MAX_INVENTORY];
+ memset(eq_n,0,sizeof(eq_n));
+ //先ず装備しているアイテム数をカウント
+ for(i=0;i<MAX_INVENTORY;i++){
+ int k;
+ if( (type == 1 && !sd->status.inventory[i].equip)
+ || (type == 2 && sd->status.inventory[i].equip)
+ || type == 3){
+ //InventoryIndexを格納
+ for(k=0;k<MAX_INVENTORY;k++){
+ if(eq_n[k] <= 0){
+ eq_n[k]=i;
+ break;
+ }
+ }
+ eq_num++;
+ }
+ }
+ if(eq_num > 0){
+ int n = eq_n[rand()%eq_num];//該当アイテムの中からランダム
+ if(rand()%10000 < per){
+ if(sd->status.inventory[n].equip)
+ pc_unequipitem(sd,n,0);
+ pc_dropitem(sd,n,1);
+ }
+ }
+ }
+ else if(id > 0){
+ for(i=0;i<MAX_INVENTORY;i++){
+ if(sd->status.inventory[i].nameid == id//ItemIDが一致していて
+ && rand()%10000 < per//ドロップ率判定もOKで
+ && ((type == 1 && !sd->status.inventory[i].equip)//タイプ判定もOKならドロップ
+ || (type == 2 && sd->status.inventory[i].equip)
+ || type == 3) ){
+ if(sd->status.inventory[i].equip)
+ pc_unequipitem(sd,i,0);
+ pc_dropitem(sd,i,1);
+ break;
+ }
+ }
+ }
+ }
+ }
+ // pvp
+ if( map[sd->bl.m].flag.pvp && !battle_config.pk_mode){ // disable certain pvp functions on pk_mode [Valaris]
+ //ランキング計算
+ if(!map[sd->bl.m].flag.pvp_nocalcrank){
+ sd->pvp_point-=5;
+ if(src && src->type==BL_PC )
+ ((struct map_session_data *)src)->pvp_point++;
+ //} //fixed wrong '{' placement by Lupus
+ pc_setdead(sd);
+ }
+ // 強制送還
+ if( sd->pvp_point < 0 ){
+ sd->pvp_point=0;
+ pc_setstand(sd);
+ pc_setrestartvalue(sd,3);
+ pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,0);
+ }
+ }
+ //GvG
+ if(map[sd->bl.m].flag.gvg){
+ pc_setstand(sd);
+ pc_setrestartvalue(sd,3);
+ pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,0);
+ }
+
+ return 0;
+}
+
+//
+// script関 連
+//
+/*==========================================
+ * script用PCステータス読み出し
+ *------------------------------------------
+ */
+int pc_readparam(struct map_session_data *sd,int type)
+{
+ int val=0;
+ struct pc_base_job s_class;
+
+ s_class = pc_calc_base_job(sd->status.class);
+
+ nullpo_retr(0, sd);
+
+ switch(type){
+ case SP_SKILLPOINT:
+ val= sd->status.skill_point;
+ break;
+ case SP_STATUSPOINT:
+ val= sd->status.status_point;
+ break;
+ case SP_ZENY:
+ val= sd->status.zeny;
+ break;
+ case SP_BASELEVEL:
+ val= sd->status.base_level;
+ break;
+ case SP_JOBLEVEL:
+ val= sd->status.job_level;
+ break;
+ case SP_CLASS:
+ if(val>=24 && val < 45)
+ val+=3978;
+ else
+ val= sd->status.class;
+ break;
+ case SP_UPPER:
+ val= s_class.upper;
+ break;
+ case SP_SEX:
+ val= sd->sex;
+ break;
+ case SP_WEIGHT:
+ val= sd->weight;
+ break;
+ case SP_MAXWEIGHT:
+ val= sd->max_weight;
+ break;
+ case SP_BASEEXP:
+ val= sd->status.base_exp;
+ break;
+ case SP_JOBEXP:
+ val= sd->status.job_exp;
+ break;
+ case SP_NEXTBASEEXP:
+ val= pc_nextbaseexp(sd);
+ break;
+ case SP_NEXTJOBEXP:
+ val= pc_nextjobexp(sd);
+ break;
+ case SP_HP:
+ val= sd->status.hp;
+ break;
+ case SP_MAXHP:
+ val= sd->status.max_hp;
+ break;
+ case SP_SP:
+ val= sd->status.sp;
+ break;
+ case SP_MAXSP:
+ val= sd->status.max_sp;
+ break;
+ case SP_STR:
+ val= sd->status.str;
+ break;
+ case SP_AGI:
+ val= sd->status.agi;
+ break;
+ case SP_VIT:
+ val= sd->status.vit;
+ break;
+ case SP_INT:
+ val= sd->status.int_;
+ break;
+ case SP_DEX:
+ val= sd->status.dex;
+ break;
+ case SP_LUK:
+ val= sd->status.luk;
+ break;
+ case SP_FAME:
+ val= sd->fame;
+ break;
+ }
+
+ return val;
+}
+
+/*==========================================
+ * script用PCステータス設定
+ *------------------------------------------
+ */
+int pc_setparam(struct map_session_data *sd,int type,int val)
+{
+ int i = 0,up_level = 50;
+ struct pc_base_job s_class;
+
+ nullpo_retr(0, sd);
+
+ s_class = pc_calc_base_job(sd->status.class);
+
+ switch(type){
+ case SP_BASELEVEL:
+ if (val > sd->status.base_level) {
+ for (i = 1; i <= (val - sd->status.base_level); i++)
+ sd->status.status_point += (sd->status.base_level + i + 14) / 5 ;
+ }
+ sd->status.base_level = val;
+ sd->status.base_exp = 0;
+ clif_updatestatus(sd, SP_BASELEVEL);
+ clif_updatestatus(sd, SP_NEXTBASEEXP);
+ clif_updatestatus(sd, SP_STATUSPOINT);
+ clif_updatestatus(sd, SP_BASEEXP);
+ pc_calcstatus(sd, 0);
+ pc_heal(sd, sd->status.max_hp, sd->status.max_sp);
+ break;
+ case SP_JOBLEVEL:
+ if (sd->status.class == 0)
+ up_level -= 40;
+ if ((sd->status.class == 23) || (sd->status.class >= 4001 && sd->status.class <= 4022))
+ up_level += 20;
+ if (val >= sd->status.job_level) {
+ if (val > up_level)val = up_level;
+ sd->status.skill_point += (val-sd->status.job_level);
+ sd->status.job_level = val;
+ sd->status.job_exp = 0;
+ clif_updatestatus(sd, SP_JOBLEVEL);
+ clif_updatestatus(sd, SP_NEXTJOBEXP);
+ clif_updatestatus(sd, SP_JOBEXP);
+ clif_updatestatus(sd, SP_SKILLPOINT);
+ pc_calcstatus(sd, 0);
+ clif_misceffect(&sd->bl, 1);
+ } else {
+ sd->status.job_level = val;
+ sd->status.job_exp = 0;
+ clif_updatestatus(sd, SP_JOBLEVEL);
+ clif_updatestatus(sd, SP_NEXTJOBEXP);
+ clif_updatestatus(sd, SP_JOBEXP);
+ pc_calcstatus(sd, 0);
+ }
+ clif_updatestatus(sd,type);
+ break;
+ case SP_SKILLPOINT:
+ sd->status.skill_point = val;
+ break;
+ case SP_STATUSPOINT:
+ sd->status.status_point = val;
+ break;
+ case SP_ZENY:
+ sd->status.zeny = val;
+ break;
+ case SP_BASEEXP:
+ if(pc_nextbaseexp(sd) > 0) {
+ sd->status.base_exp = val;
+ if(sd->status.base_exp < 0)
+ sd->status.base_exp=0;
+ pc_checkbaselevelup(sd);
+ }
+ break;
+ case SP_JOBEXP:
+ if(pc_nextjobexp(sd) > 0) {
+ sd->status.job_exp = val;
+ if(sd->status.job_exp < 0)
+ sd->status.job_exp=0;
+ pc_checkjoblevelup(sd);
+ }
+ break;
+ case SP_SEX:
+ sd->sex = val;
+ break;
+ case SP_WEIGHT:
+ sd->weight = val;
+ break;
+ case SP_MAXWEIGHT:
+ sd->max_weight = val;
+ break;
+ case SP_HP:
+ sd->status.hp = val;
+ break;
+ case SP_MAXHP:
+ sd->status.max_hp = val;
+ break;
+ case SP_SP:
+ sd->status.sp = val;
+ break;
+ case SP_MAXSP:
+ sd->status.max_sp = val;
+ break;
+ case SP_STR:
+ sd->status.str = val;
+ break;
+ case SP_AGI:
+ sd->status.agi = val;
+ break;
+ case SP_VIT:
+ sd->status.vit = val;
+ break;
+ case SP_INT:
+ sd->status.int_ = val;
+ break;
+ case SP_DEX:
+ sd->status.dex = val;
+ break;
+ case SP_LUK:
+ sd->status.luk = val;
+ break;
+ case SP_FAME:
+ sd->fame = val;
+ break;
+ }
+ clif_updatestatus(sd,type);
+
+ return 0;
+}
+
+/*==========================================
+ * HP/SP回復
+ *------------------------------------------
+ */
+int pc_heal(struct map_session_data *sd,int hp,int sp)
+{
+// if(battle_config.battle_log)
+// printf("heal %d %d\n",hp,sp);
+
+ nullpo_retr(0, sd);
+
+ if(pc_checkoverhp(sd)) {
+ if(hp > 0)
+ hp = 0;
+ }
+ if(pc_checkoversp(sd)) {
+ if(sp > 0)
+ sp = 0;
+ }
+
+ if(sd->sc_data && sd->sc_data[SC_BERSERK].timer!=-1) //バーサーク中は回復させないらしい
+ return 0;
+
+ if(hp+sd->status.hp>sd->status.max_hp)
+ hp=sd->status.max_hp-sd->status.hp;
+ if(sp+sd->status.sp>sd->status.max_sp)
+ sp=sd->status.max_sp-sd->status.sp;
+ sd->status.hp+=hp;
+ if(sd->status.hp <= 0) {
+ sd->status.hp = 0;
+ pc_damage(NULL,sd,1);
+ hp = 0;
+ }
+ sd->status.sp+=sp;
+ if(sd->status.sp <= 0)
+ sd->status.sp = 0;
+ if(hp)
+ clif_updatestatus(sd,SP_HP);
+ if(sp)
+ clif_updatestatus(sd,SP_SP);
+
+ if(sd->status.party_id>0) { // on-the-fly party hp updates [Valaris]
+ struct party *p=party_search(sd->status.party_id);
+ if(p!=NULL) clif_party_hp(p,sd);
+ } // end addition [Valaris]
+
+ return hp + sp;
+}
+
+/*==========================================
+ * HP/SP回復
+ *------------------------------------------
+ */
+int pc_itemheal(struct map_session_data *sd,int hp,int sp)
+{
+ int bonus;
+// if(battle_config.battle_log)
+// printf("heal %d %d\n",hp,sp);
+
+ nullpo_retr(0, sd);
+
+ if(sd->sc_data && sd->sc_data[SC_GOSPEL].timer!=-1) //バーサーク中は回復させないらしい
+ return 0;
+
+ if(sd->state.potionpitcher_flag) {
+ sd->potion_hp = hp;
+ sd->potion_sp = sp;
+ return 0;
+ }
+
+ if(pc_checkoverhp(sd)) {
+ if(hp > 0)
+ hp = 0;
+ }
+ if(pc_checkoversp(sd)) {
+ if(sp > 0)
+ sp = 0;
+ }
+ if(hp > 0) {
+ bonus = (sd->paramc[2]<<1) + 100 + pc_checkskill(sd,SM_RECOVERY)*10;
+ if(bonus != 100)
+ hp = hp * bonus / 100;
+ bonus = 100 + pc_checkskill(sd,AM_LEARNINGPOTION)*5;
+ if(bonus != 100)
+ hp = hp * bonus / 100;
+ }
+ if(sp > 0) {
+ bonus = (sd->paramc[3]<<1) + 100 + pc_checkskill(sd,MG_SRECOVERY)*10;
+ if(bonus != 100)
+ sp = sp * bonus / 100;
+ bonus = 100 + pc_checkskill(sd,AM_LEARNINGPOTION)*5;
+ if(bonus != 100)
+ sp = sp * bonus / 100;
+ }
+ if(hp+sd->status.hp>sd->status.max_hp)
+ hp=sd->status.max_hp-sd->status.hp;
+ if(sp+sd->status.sp>sd->status.max_sp)
+ sp=sd->status.max_sp-sd->status.sp;
+ sd->status.hp+=hp;
+ if(sd->status.hp <= 0) {
+ sd->status.hp = 0;
+ pc_damage(NULL,sd,1);
+ hp = 0;
+ }
+ sd->status.sp+=sp;
+ if(sd->status.sp <= 0)
+ sd->status.sp = 0;
+ if(hp)
+ clif_updatestatus(sd,SP_HP);
+ if(sp)
+ clif_updatestatus(sd,SP_SP);
+
+ return 0;
+}
+
+/*==========================================
+ * HP/SP回復
+ *------------------------------------------
+ */
+int pc_percentheal(struct map_session_data *sd,int hp,int sp)
+{
+ nullpo_retr(0, sd);
+
+ if(sd->state.potionpitcher_flag) {
+ sd->potion_per_hp = hp;
+ sd->potion_per_sp = sp;
+ return 0;
+ }
+
+ if(pc_checkoverhp(sd)) {
+ if(hp > 0)
+ hp = 0;
+ }
+ if(pc_checkoversp(sd)) {
+ if(sp > 0)
+ sp = 0;
+ }
+ if(hp) {
+ if(hp >= 100) {
+ sd->status.hp = sd->status.max_hp;
+ }
+ else if(hp <= -100) {
+ sd->status.hp = 0;
+ pc_damage(NULL,sd,1);
+ }
+ else {
+ sd->status.hp += sd->status.max_hp*hp/100;
+ if(sd->status.hp > sd->status.max_hp)
+ sd->status.hp = sd->status.max_hp;
+ if(sd->status.hp <= 0) {
+ sd->status.hp = 0;
+ pc_damage(NULL,sd,1);
+ hp = 0;
+ }
+ }
+ }
+ if(sp) {
+ if(sp >= 100) {
+ sd->status.sp = sd->status.max_sp;
+ }
+ else if(sp <= -100) {
+ sd->status.sp = 0;
+ }
+ else {
+ sd->status.sp += sd->status.max_sp*sp/100;
+ if(sd->status.sp > sd->status.max_sp)
+ sd->status.sp = sd->status.max_sp;
+ if(sd->status.sp < 0)
+ sd->status.sp = 0;
+ }
+ }
+ if(hp)
+ clif_updatestatus(sd,SP_HP);
+ if(sp)
+ clif_updatestatus(sd,SP_SP);
+
+ return 0;
+}
+
+/*==========================================
+ * 職変更
+ * 引数 job 職業 0〜23
+ * upper 通常 0, 転生 1, 養子 2, そのまま -1
+ *------------------------------------------
+ */
+int pc_jobchange(struct map_session_data *sd,int job, int upper)
+{
+ int i;
+ int b_class = 0;
+ //転生や養子の場合の元の職業を算出する
+ struct pc_base_job s_class = pc_calc_base_job(sd->status.class);
+
+ nullpo_retr(0, sd);
+
+ if((job > 23) && (job < 68))
+ job += 3977;
+
+ if((job > 69) && (job < 4000))
+ return 1;
+
+ if(upper < 0) //現在転生かどうかを判断する
+ upper = s_class.upper;
+
+ if(upper == 0){ //通常職ならjobそのまんま
+ b_class = job;
+ }else if(upper == 1){
+ if(job == 23){ //転生にスパノビは存在しないのでお断り
+ return 1;
+ }else{
+ b_class = job + 4001;
+ }
+ }else if(upper == 2){ //養子に結婚はないけどどうせ次で蹴られるからいいや
+ b_class = (job==23)?job + 4022:job + 4023;
+ }else{
+ return 1;
+ }
+
+ if((sd->status.sex == 0 && job == 19) || (sd->status.sex == 1 && job == 20) ||
+ (sd->status.sex == 0 && job == 4020) || (sd->status.sex == 1 && job == 4021) ||
+ job ==22 || sd->status.class == b_class) //♀はバードになれない、♂はダンサーになれない、結婚衣裳もお断り
+ return 1;
+
+ sd->status.class = sd->view_class = b_class;
+
+ sd->status.job_level=1;
+ sd->status.job_exp=0;
+ clif_updatestatus(sd,SP_JOBLEVEL);
+ clif_updatestatus(sd,SP_JOBEXP);
+ clif_updatestatus(sd,SP_NEXTJOBEXP);
+
+ for(i=0;i<11;i++) {
+ if(sd->equip_index[i] >= 0)
+ if(!pc_isequip(sd,sd->equip_index[i]))
+ pc_unequipitem(sd,sd->equip_index[i],1); // 装備外し
+ }
+
+ clif_changelook(&sd->bl,LOOK_BASE,sd->view_class); // move sprite update to prevent client crashes with incompatible equipment [Valaris]
+ if(sd->status.clothes_color > 0)
+ clif_changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->status.clothes_color);
+ if(battle_config.muting_players && sd->status.manner < 0)
+ clif_changestatus(&sd->bl,SP_MANNER,sd->status.manner);
+
+ pc_calcstatus(sd,0);
+ pc_checkallowskill(sd);
+ pc_equiplookall(sd);
+ clif_equiplist(sd);
+
+ if(pc_isriding(sd)) { // remove peco status if changing into invalid class [Valaris]
+ if(!(pc_checkskill(sd,KN_RIDING)))
+ pc_setoption(sd,sd->status.option|-0x0000);
+ if(pc_checkskill(sd,KN_RIDING)>0)
+ pc_setriding(sd);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 見た目変更
+ *------------------------------------------
+ */
+int pc_equiplookall(struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+
+#if PACKETVER < 4
+ clif_changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon);
+ clif_changelook(&sd->bl,LOOK_SHIELD,sd->status.shield);
+#else
+ clif_changelook(&sd->bl,LOOK_WEAPON,0);
+ clif_changelook(&sd->bl,LOOK_SHOES,0);
+#endif
+ clif_changelook(&sd->bl,LOOK_HEAD_BOTTOM,sd->status.head_bottom);
+ clif_changelook(&sd->bl,LOOK_HEAD_TOP,sd->status.head_top);
+ clif_changelook(&sd->bl,LOOK_HEAD_MID,sd->status.head_mid);
+
+ return 0;
+}
+
+/*==========================================
+ * 見た目変更
+ *------------------------------------------
+ */
+int pc_changelook(struct map_session_data *sd,int type,int val)
+{
+ nullpo_retr(0, sd);
+
+ switch(type){
+ case LOOK_HAIR:
+ sd->status.hair=val;
+ break;
+ case LOOK_WEAPON:
+ sd->status.weapon=val;
+ break;
+ case LOOK_HEAD_BOTTOM:
+ sd->status.head_bottom=val;
+ break;
+ case LOOK_HEAD_TOP:
+ sd->status.head_top=val;
+ break;
+ case LOOK_HEAD_MID:
+ sd->status.head_mid=val;
+ break;
+ case LOOK_HAIR_COLOR:
+ sd->status.hair_color=val;
+ break;
+ case LOOK_CLOTHES_COLOR:
+ sd->status.clothes_color=val;
+ break;
+ case LOOK_SHIELD:
+ sd->status.shield=val;
+ break;
+ case LOOK_SHOES:
+ break;
+ }
+ clif_changelook(&sd->bl,type,val);
+
+ return 0;
+}
+
+/*==========================================
+ * 付属品(鷹,ペコ,カート)設定
+ *------------------------------------------
+ */
+int pc_setoption(struct map_session_data *sd,int type)
+{
+ nullpo_retr(0, sd);
+
+ sd->status.option=type;
+ clif_changeoption(&sd->bl);
+ pc_calcstatus(sd,0);
+
+ return 0;
+}
+
+/*==========================================
+ * カート設定
+ *------------------------------------------
+ */
+int pc_setcart(struct map_session_data *sd,int type)
+{
+ int cart[6]={0x0000,0x0008,0x0080,0x0100,0x0200,0x0400};
+
+ nullpo_retr(0, sd);
+
+ if(pc_checkskill(sd,MC_PUSHCART)>0){ // プッシュカートスキル所持
+ if(!pc_iscarton(sd)){ // カートを付けていない
+ pc_setoption(sd,cart[type]);
+ clif_cart_itemlist(sd);
+ clif_cart_equiplist(sd);
+ clif_updatestatus(sd,SP_CARTINFO);
+ clif_status_change(&sd->bl,0x0c,0);
+ }
+ else{
+ pc_setoption(sd,cart[type]);
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 鷹設定
+ *------------------------------------------
+ */
+int pc_setfalcon(struct map_session_data *sd)
+{
+ if(pc_checkskill(sd,HT_FALCON)>0){ // ファルコンマスタリースキル所持
+ pc_setoption(sd,sd->status.option|0x0010);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * ペコペコ設定
+ *------------------------------------------
+ */
+int pc_setriding(struct map_session_data *sd)
+{
+ if(sd->disguise > 0) { // temporary prevention of crash caused by peco + disguise, will look into a better solution [Valaris]
+ clif_displaymessage(sd->fd, "Cannot mount a Peco while in disguise.");
+ return 0;
+ }
+
+ if((pc_checkskill(sd,KN_RIDING)>0)){ // ライディングスキル所持
+ pc_setoption(sd,sd->status.option|0x0020);
+
+ if(sd->status.class==7)
+ sd->status.class=sd->view_class=13;
+
+ if(sd->status.class==14)
+ sd->status.class=sd->view_class=21;
+
+ if(sd->status.class==4008)
+ sd->status.class=sd->view_class=4014;
+
+ if(sd->status.class==4015)
+ sd->status.class=sd->view_class=4022;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * script用変数の値を読む
+ *------------------------------------------
+ */
+int pc_readreg(struct map_session_data *sd,int reg)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ for(i=0;i<sd->reg_num;i++)
+ if(sd->reg[i].index==reg)
+ return sd->reg[i].data;
+
+ return 0;
+}
+/*==========================================
+ * script用変数の値を設定
+ *------------------------------------------
+ */
+int pc_setreg(struct map_session_data *sd,int reg,int val)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ for (i = 0; i < sd->reg_num; i++) {
+ if (sd->reg[i].index == reg){
+ sd->reg[i].data = val;
+ return 0;
+ }
+ }
+ sd->reg_num++;
+ sd->reg = realloc(sd->reg, sizeof(*(sd->reg)) * sd->reg_num);
+ if (sd->reg == NULL){
+ printf("out of memory : pc_setreg\n");
+ exit(1);
+ }
+/* memset(sd->reg + (sd->reg_num - 1) * sizeof(*(sd->reg)), 0,
+ sizeof(*(sd->reg)));
+*/
+ sd->reg[i].index = reg;
+ sd->reg[i].data = val;
+
+ return 0;
+}
+
+/*==========================================
+ * script用文字列変数の値を読む
+ *------------------------------------------
+ */
+char *pc_readregstr(struct map_session_data *sd,int reg)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ for(i=0;i<sd->regstr_num;i++)
+ if(sd->regstr[i].index==reg)
+ return sd->regstr[i].data;
+
+ return NULL;
+}
+/*==========================================
+ * script用文字列変数の値を設定
+ *------------------------------------------
+ */
+int pc_setregstr(struct map_session_data *sd,int reg,char *str)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if(strlen(str)+1 >= sizeof(sd->regstr[0].data)){
+ printf("pc_setregstr: string too long !\n");
+ return 0;
+ }
+
+ for(i=0;i<sd->regstr_num;i++)
+ if(sd->regstr[i].index==reg){
+ strcpy(sd->regstr[i].data,str);
+ return 0;
+ }
+ sd->regstr_num++;
+ sd->regstr = realloc(sd->regstr, sizeof(sd->regstr[0]) * sd->regstr_num);
+ if(sd->regstr==NULL){
+ printf("out of memory : pc_setreg\n");
+ exit(1);
+ }
+/* memset(sd->reg + (sd->reg_num - 1) * sizeof(*(sd->reg)), 0,
+ sizeof(*(sd->reg)));
+*/
+ sd->regstr[i].index=reg;
+ strcpy(sd->regstr[i].data,str);
+
+ return 0;
+}
+
+/*==========================================
+ * script用グローバル変数の値を読む
+ *------------------------------------------
+ */
+int pc_readglobalreg(struct map_session_data *sd,char *reg)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ for(i=0;i<sd->status.global_reg_num;i++){
+ if(strcmp(sd->status.global_reg[i].str,reg)==0)
+ return sd->status.global_reg[i].value;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * script用グローバル変数の値を設定
+ *------------------------------------------
+ */
+int pc_setglobalreg(struct map_session_data *sd,char *reg,int val)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ //PC_DIE_COUNTERがスクリプトなどで変更された時の処理
+ if(strcmp(reg,"PC_DIE_COUNTER") == 0 && sd->die_counter != val){
+ sd->die_counter = val;
+ pc_calcstatus(sd,0);
+ }
+ if(val==0){
+ for(i=0;i<sd->status.global_reg_num;i++){
+ if(strcmp(sd->status.global_reg[i].str,reg)==0){
+ sd->status.global_reg[i]=sd->status.global_reg[sd->status.global_reg_num-1];
+ sd->status.global_reg_num--;
+ break;
+ }
+ }
+ return 0;
+ }
+ for(i=0;i<sd->status.global_reg_num;i++){
+ if(strcmp(sd->status.global_reg[i].str,reg)==0){
+ sd->status.global_reg[i].value=val;
+ return 0;
+ }
+ }
+ if(sd->status.global_reg_num<GLOBAL_REG_NUM){
+ strcpy(sd->status.global_reg[i].str,reg);
+ sd->status.global_reg[i].value=val;
+ sd->status.global_reg_num++;
+ return 0;
+ }
+ if(battle_config.error_log)
+ printf("pc_setglobalreg : couldn't set %s (GLOBAL_REG_NUM = %d)\n", reg, GLOBAL_REG_NUM);
+
+ return 1;
+}
+
+/*==========================================
+ * script用アカウント変数の値を読む
+ *------------------------------------------
+ */
+int pc_readaccountreg(struct map_session_data *sd,char *reg)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ for(i=0;i<sd->status.account_reg_num;i++){
+ if(strcmp(sd->status.account_reg[i].str,reg)==0)
+ return sd->status.account_reg[i].value;
+ }
+
+ return 0;
+}
+/*==========================================
+ * script用アカウント変数の値を設定
+ *------------------------------------------
+ */
+int pc_setaccountreg(struct map_session_data *sd,char *reg,int val)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ if(val==0){
+ for(i=0;i<sd->status.account_reg_num;i++){
+ if(strcmp(sd->status.account_reg[i].str,reg)==0){
+ sd->status.account_reg[i]=sd->status.account_reg[sd->status.account_reg_num-1];
+ sd->status.account_reg_num--;
+ break;
+ }
+ }
+ intif_saveaccountreg(sd);
+ return 0;
+ }
+ for(i=0;i<sd->status.account_reg_num;i++){
+ if(strcmp(sd->status.account_reg[i].str,reg)==0){
+ sd->status.account_reg[i].value=val;
+ intif_saveaccountreg(sd);
+ return 0;
+ }
+ }
+ if(sd->status.account_reg_num<ACCOUNT_REG_NUM){
+ strcpy(sd->status.account_reg[i].str,reg);
+ sd->status.account_reg[i].value=val;
+ sd->status.account_reg_num++;
+ intif_saveaccountreg(sd);
+ return 0;
+ }
+ if(battle_config.error_log)
+ printf("pc_setaccountreg : couldn't set %s (ACCOUNT_REG_NUM = %d)\n", reg, ACCOUNT_REG_NUM);
+
+ return 1;
+}
+/*==========================================
+ * script用アカウント変数2の値を読む
+ *------------------------------------------
+ */
+int pc_readaccountreg2(struct map_session_data *sd,char *reg)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ for(i=0;i<sd->status.account_reg2_num;i++){
+ if(strcmp(sd->status.account_reg2[i].str,reg)==0)
+ return sd->status.account_reg2[i].value;
+ }
+
+ return 0;
+}
+/*==========================================
+ * script用アカウント変数2の値を設定
+ *------------------------------------------
+ */
+int pc_setaccountreg2(struct map_session_data *sd,char *reg,int val)
+{
+ int i;
+
+ nullpo_retr(1, sd);
+
+ if(val==0){
+ for(i=0;i<sd->status.account_reg2_num;i++){
+ if(strcmp(sd->status.account_reg2[i].str,reg)==0){
+ sd->status.account_reg2[i]=sd->status.account_reg2[sd->status.account_reg2_num-1];
+ sd->status.account_reg2_num--;
+ break;
+ }
+ }
+ chrif_saveaccountreg2(sd);
+ return 0;
+ }
+ for(i=0;i<sd->status.account_reg2_num;i++){
+ if(strcmp(sd->status.account_reg2[i].str,reg)==0){
+ sd->status.account_reg2[i].value=val;
+ chrif_saveaccountreg2(sd);
+ return 0;
+ }
+ }
+ if(sd->status.account_reg2_num<ACCOUNT_REG2_NUM){
+ strcpy(sd->status.account_reg2[i].str,reg);
+ sd->status.account_reg2[i].value=val;
+ sd->status.account_reg2_num++;
+ chrif_saveaccountreg2(sd);
+ return 0;
+ }
+ if(battle_config.error_log)
+ printf("pc_setaccountreg2 : couldn't set %s (ACCOUNT_REG2_NUM = %d)\n", reg, ACCOUNT_REG2_NUM);
+
+ return 1;
+}
+/*==========================================
+ * 精錬成功率
+ *------------------------------------------
+ */
+int pc_percentrefinery(struct map_session_data *sd,struct item *item)
+{
+ int percent;
+
+ nullpo_retr(0, item);
+ percent=percentrefinery[itemdb_wlv(item->nameid)][(int)item->refine];
+
+ percent += pc_checkskill(sd,BS_WEAPONRESEARCH); // 武器研究スキル所持
+
+ // 確率の有効範囲チェック
+ if( percent > 100 ){
+ percent = 100;
+ }
+ if( percent < 0 ){
+ percent = 0;
+ }
+
+ return percent;
+}
+
+/*==========================================
+ * イベントタイマー処理
+ *------------------------------------------
+ */
+int pc_eventtimer(int tid,unsigned int tick,int id,int data)
+{
+ struct map_session_data *sd=map_id2sd(id);
+ int i;
+ if(sd==NULL)
+ return 0;
+
+ for(i=0;i<MAX_EVENTTIMER;i++){
+ if( sd->eventtimer[i]==tid ){
+ sd->eventtimer[i]=-1;
+ npc_event(sd,(const char *)data,0);
+ break;
+ }
+ }
+ free((void *)data);
+ if(i==MAX_EVENTTIMER) {
+ if(battle_config.error_log)
+ printf("pc_eventtimer: no such event timer\n");
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * イベントタイマー追加
+ *------------------------------------------
+ */
+int pc_addeventtimer(struct map_session_data *sd,int tick,const char *name)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ for(i=0;i<MAX_EVENTTIMER;i++)
+ if( sd->eventtimer[i]==-1 )
+ break;
+ if(i<MAX_EVENTTIMER){
+ char *evname=(char *)aCalloc(24,sizeof(char));
+ memcpy(evname,name,24);
+ sd->eventtimer[i]=add_timer(gettick()+tick,
+ pc_eventtimer,sd->bl.id,(int)evname);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * イベントタイマー削除
+ *------------------------------------------
+ */
+int pc_deleventtimer(struct map_session_data *sd,const char *name)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ for(i=0;i<MAX_EVENTTIMER;i++)
+ if( sd->eventtimer[i]!=-1 && strcmp(
+ (char *)(get_timer(sd->eventtimer[i])->data), name)==0 ){
+ delete_timer(sd->eventtimer[i],pc_eventtimer);
+ sd->eventtimer[i]=-1;
+ break;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * イベントタイマーカウント値追加
+ *------------------------------------------
+ */
+int pc_addeventtimercount(struct map_session_data *sd,const char *name,int tick)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ for(i=0;i<MAX_EVENTTIMER;i++)
+ if( sd->eventtimer[i]!=-1 && strcmp(
+ (char *)(get_timer(sd->eventtimer[i])->data), name)==0 ){
+ addtick_timer(sd->eventtimer[i],tick);
+ break;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * イベントタイマー全削除
+ *------------------------------------------
+ */
+int pc_cleareventtimer(struct map_session_data *sd)
+{
+ int i;
+
+ nullpo_retr(0, sd);
+
+ for(i=0;i<MAX_EVENTTIMER;i++)
+ if( sd->eventtimer[i]!=-1 ){
+ delete_timer(sd->eventtimer[i],pc_eventtimer);
+ sd->eventtimer[i]=-1;
+ }
+
+ return 0;
+}
+
+//
+// 装 備物
+//
+/*==========================================
+ * アイテムを装備する
+ *------------------------------------------
+ */
+int pc_equipitem(struct map_session_data *sd,int n,int pos)
+{
+ int i,nameid, arrow;
+ struct item_data *id;
+ //転生や養子の場合の元の職業を算出する
+
+ nullpo_retr(0, sd);
+
+ nameid = sd->status.inventory[n].nameid;
+ id = sd->inventory_data[n];
+ pos = pc_equippoint(sd,n);
+ if(battle_config.battle_log)
+ printf("equip %d(%d) %x:%x\n",nameid,n,id->equip,pos);
+ if(!pc_isequip(sd,n) || !pos || sd->status.inventory[n].attribute==1 ) { // [Valaris]
+ clif_equipitemack(sd,n,0,0); // fail
+ return 0;
+ }
+
+// -- moonsoul (if player is berserk then cannot equip)
+//
+ if(sd->sc_data[SC_BERSERK].timer!=-1){
+ clif_equipitemack(sd,n,0,0); // fail
+ return 0;
+ }
+
+ if(pos==0x88){ // アクセサリ用例外処理
+ int epor=0;
+ if(sd->equip_index[0] >= 0)
+ epor |= sd->status.inventory[sd->equip_index[0]].equip;
+ if(sd->equip_index[1] >= 0)
+ epor |= sd->status.inventory[sd->equip_index[1]].equip;
+ epor &= 0x88;
+ pos = epor == 0x08 ? 0x80 : 0x08;
+ }
+
+ // 二刀流処理
+ if ((pos==0x22) // 一応、装備要求箇所が二刀流武器かチェックする
+ && (id->equip==2) // 単 手武器
+ && (pc_checkskill(sd, AS_LEFT) > 0 || sd->status.class == 12) ) // 左手修錬有
+ {
+ int tpos=0;
+ if(sd->equip_index[8] >= 0)
+ tpos |= sd->status.inventory[sd->equip_index[8]].equip;
+ if(sd->equip_index[9] >= 0)
+ tpos |= sd->status.inventory[sd->equip_index[9]].equip;
+ tpos &= 0x02;
+ pos = tpos == 0x02 ? 0x20 : 0x02;
+ }
+
+ arrow=pc_search_inventory(sd,pc_checkequip(sd,9)); // Added by RoVeRT
+ for(i=0;i<11;i++) {
+ if(sd->equip_index[i] >= 0 && sd->status.inventory[sd->equip_index[i]].equip&pos) {
+ pc_unequipitem(sd,sd->equip_index[i],1);
+ }
+ }
+ // 弓矢装備
+ if(pos==0x8000){
+ clif_arrowequip(sd,n);
+ clif_arrow_fail(sd,3); // 3=矢が装備できました
+ }
+ else
+ clif_equipitemack(sd,n,pos,1);
+
+ for(i=0;i<11;i++) {
+ if(pos & equip_pos[i])
+ sd->equip_index[i] = n;
+ }
+ sd->status.inventory[n].equip=pos;
+
+ if(sd->status.inventory[n].equip & 0x0002) {
+ if(sd->inventory_data[n])
+ sd->weapontype1 = sd->inventory_data[n]->look;
+ else
+ sd->weapontype1 = 0;
+ pc_calcweapontype(sd);
+ clif_changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon);
+ }
+ if(sd->status.inventory[n].equip & 0x0020) {
+ if(sd->inventory_data[n]) {
+ if(sd->inventory_data[n]->type == 4) {
+ sd->status.shield = 0;
+ if(sd->status.inventory[n].equip == 0x0020)
+ sd->weapontype2 = sd->inventory_data[n]->look;
+ else
+ sd->weapontype2 = 0;
+ }
+ else if(sd->inventory_data[n]->type == 5) {
+ sd->status.shield = sd->inventory_data[n]->look;
+ sd->weapontype2 = 0;
+ }
+ }
+ else
+ sd->status.shield = sd->weapontype2 = 0;
+ pc_calcweapontype(sd);
+ clif_changelook(&sd->bl,LOOK_SHIELD,sd->status.shield);
+ }
+ if(sd->status.inventory[n].equip & 0x0001) {
+ if(sd->inventory_data[n])
+ sd->status.head_bottom = sd->inventory_data[n]->look;
+ else
+ sd->status.head_bottom = 0;
+ clif_changelook(&sd->bl,LOOK_HEAD_BOTTOM,sd->status.head_bottom);
+ }
+ if(sd->status.inventory[n].equip & 0x0100) {
+ if(sd->inventory_data[n])
+ sd->status.head_top = sd->inventory_data[n]->look;
+ else
+ sd->status.head_top = 0;
+ clif_changelook(&sd->bl,LOOK_HEAD_TOP,sd->status.head_top);
+ }
+ if(sd->status.inventory[n].equip & 0x0200) {
+ if(sd->inventory_data[n])
+ sd->status.head_mid = sd->inventory_data[n]->look;
+ else
+ sd->status.head_mid = 0;
+ clif_changelook(&sd->bl,LOOK_HEAD_MID,sd->status.head_mid);
+ }
+ if(sd->status.inventory[n].equip & 0x0040)
+ clif_changelook(&sd->bl,LOOK_SHOES,0);
+
+ pc_checkallowskill(sd); // 装備品でスキルか解除されるかチェック
+ if (itemdb_look(sd->status.inventory[n].nameid) == 11 && arrow){ // Added by RoVeRT
+ clif_arrowequip(sd,arrow);
+ sd->status.inventory[arrow].equip=32768;
+ }
+ pc_calcstatus(sd,0);
+
+ if(sd->special_state.infinite_endure) {
+ if(sd->sc_data[SC_ENDURE].timer == -1)
+ skill_status_change_start(&sd->bl,SC_ENDURE,10,1,0,0,0,0);
+ }
+ else {
+ if(sd->sc_data[SC_ENDURE].timer != -1 && sd->sc_data[SC_ENDURE].val2)
+ skill_status_change_end(&sd->bl,SC_ENDURE,-1);
+ }
+
+ if(sd->sc_data[SC_SIGNUMCRUCIS].timer != -1 && !battle_check_undead(7,sd->def_ele))
+ skill_status_change_end(&sd->bl,SC_SIGNUMCRUCIS,-1);
+ if(sd->sc_data[SC_DANCING].timer!=-1 && (sd->status.weapon != 13 && sd->status.weapon !=14))
+ skill_stop_dancing(&sd->bl,0);
+
+ return 0;
+}
+
+/*==========================================
+ * 装 備した物を外す
+ *------------------------------------------
+ */
+int pc_unequipitem(struct map_session_data *sd,int n,int type)
+{
+ nullpo_retr(0, sd);
+
+// -- moonsoul (if player is berserk then cannot unequip)
+//
+ if(sd->sc_data[SC_BERSERK].timer!=-1){
+ clif_unequipitemack(sd,n,0,0);
+ return 0;
+ }
+
+ if(battle_config.battle_log)
+ printf("unequip %d %x:%x\n",n,pc_equippoint(sd,n),sd->status.inventory[n].equip);
+ if(sd->status.inventory[n].equip){
+ int i;
+ for(i=0;i<11;i++) {
+ if(sd->status.inventory[n].equip & equip_pos[i])
+ sd->equip_index[i] = -1;
+ }
+ if(sd->status.inventory[n].equip & 0x0002) {
+ sd->weapontype1 = 0;
+ sd->status.weapon = sd->weapontype2;
+ pc_calcweapontype(sd);
+ clif_changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon);
+ }
+ if(sd->status.inventory[n].equip & 0x0020) {
+ sd->status.shield = sd->weapontype2 = 0;
+ pc_calcweapontype(sd);
+ clif_changelook(&sd->bl,LOOK_SHIELD,sd->status.shield);
+ }
+ if(sd->status.inventory[n].equip & 0x0001) {
+ sd->status.head_bottom = 0;
+ clif_changelook(&sd->bl,LOOK_HEAD_BOTTOM,sd->status.head_bottom);
+ }
+ if(sd->status.inventory[n].equip & 0x0100) {
+ sd->status.head_top = 0;
+ clif_changelook(&sd->bl,LOOK_HEAD_TOP,sd->status.head_top);
+ }
+ if(sd->status.inventory[n].equip & 0x0200) {
+ sd->status.head_mid = 0;
+ clif_changelook(&sd->bl,LOOK_HEAD_MID,sd->status.head_mid);
+ }
+ if(sd->status.inventory[n].equip & 0x0040)
+ clif_changelook(&sd->bl,LOOK_SHOES,0);
+
+ if(sd->sc_data[SC_BROKNWEAPON].timer != -1 && sd->status.inventory[n].equip & 0x0002 &&
+ sd->status.inventory[i].attribute==1)
+ skill_status_change_end(&sd->bl,SC_BROKNWEAPON,-1);
+
+ clif_unequipitemack(sd,n,sd->status.inventory[n].equip,1);
+ sd->status.inventory[n].equip=0;
+ if(!type)
+ pc_checkallowskill(sd);
+ if(sd->weapontype1 == 0 && sd->weapontype2 == 0)
+ skill_encchant_eremental_end(&sd->bl,-1); //武器持ち誓えは無条件で属性付与解除
+ } else {
+ clif_unequipitemack(sd,n,0,0);
+ }
+ if(!type) {
+ pc_calcstatus(sd,0);
+ if(sd->sc_data[SC_SIGNUMCRUCIS].timer != -1 && !battle_check_undead(7,sd->def_ele))
+ skill_status_change_end(&sd->bl,SC_SIGNUMCRUCIS,-1);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * アイテムのindex番号を詰めたり
+ * 装 備品の装備可能チェックを行なう
+ *------------------------------------------
+ */
+int pc_checkitem(struct map_session_data *sd)
+{
+ int i,j,k,id,calc_flag = 0;
+ struct item_data *it=NULL;
+
+ nullpo_retr(0, sd);
+
+ // 所持品空き詰め
+ for(i=j=0;i<MAX_INVENTORY;i++){
+ if( (id=sd->status.inventory[i].nameid)==0)
+ continue;
+ if( battle_config.item_check && !itemdb_available(id) ){
+ if(battle_config.error_log)
+ printf("illeagal item id %d in %d[%s] inventory.\n",id,sd->bl.id,sd->status.name);
+ pc_delitem(sd,i,sd->status.inventory[i].amount,3);
+ continue;
+ }
+ if(i>j){
+ memcpy(&sd->status.inventory[j],&sd->status.inventory[i],sizeof(struct item));
+ sd->inventory_data[j] = sd->inventory_data[i];
+ }
+ j++;
+ }
+ if(j < MAX_INVENTORY)
+ memset(&sd->status.inventory[j],0,sizeof(struct item)*(MAX_INVENTORY-j));
+ for(k=j;k<MAX_INVENTORY;k++)
+ sd->inventory_data[k] = NULL;
+
+ // カート内空き詰め
+ for(i=j=0;i<MAX_CART;i++){
+ if( (id=sd->status.cart[i].nameid)==0 )
+ continue;
+ if( battle_config.item_check && !itemdb_available(id) ){
+ if(battle_config.error_log)
+ printf("illeagal item id %d in %d[%s] cart.\n",id,sd->bl.id,sd->status.name);
+ pc_cart_delitem(sd,i,sd->status.cart[i].amount,1);
+ continue;
+ }
+ if(i>j){
+ memcpy(&sd->status.cart[j],&sd->status.cart[i],sizeof(struct item));
+ }
+ j++;
+ }
+ if(j < MAX_CART)
+ memset(&sd->status.cart[j],0,sizeof(struct item)*(MAX_CART-j));
+
+ // 装 備位置チェック
+
+ for(i=0;i<MAX_INVENTORY;i++){
+
+ it=sd->inventory_data[i];
+
+ if(sd->status.inventory[i].nameid==0)
+ continue;
+ if(sd->status.inventory[i].equip & ~pc_equippoint(sd,i)) {
+ sd->status.inventory[i].equip=0;
+ calc_flag = 1;
+ }
+ //装備制限チェック
+ if(sd->status.inventory[i].equip && map[sd->bl.m].flag.pvp && (it->flag.no_equip==1 || it->flag.no_equip==3)){//PvP制限
+ sd->status.inventory[i].equip=0;
+ calc_flag = 1;
+ }else if(sd->status.inventory[i].equip && map[sd->bl.m].flag.gvg && (it->flag.no_equip==2 || it->flag.no_equip==3)){//GvG制限
+ sd->status.inventory[i].equip=0;
+ calc_flag = 1;
+ }
+ }
+
+ pc_setequipindex(sd);
+ if(calc_flag)
+ pc_calcstatus(sd,2);
+
+ return 0;
+}
+
+int pc_checkoverhp(struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+
+ if(sd->status.hp == sd->status.max_hp)
+ return 1;
+ if(sd->status.hp > sd->status.max_hp) {
+ sd->status.hp = sd->status.max_hp;
+ clif_updatestatus(sd,SP_HP);
+ return 2;
+ }
+
+ return 0;
+}
+
+int pc_checkoversp(struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+
+ if(sd->status.sp == sd->status.max_sp)
+ return 1;
+ if(sd->status.sp > sd->status.max_sp) {
+ sd->status.sp = sd->status.max_sp;
+ clif_updatestatus(sd,SP_SP);
+ return 2;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * PVP順位計算用(foreachinarea)
+ *------------------------------------------
+ */
+int pc_calc_pvprank_sub(struct block_list *bl,va_list ap)
+{
+ struct map_session_data *sd1,*sd2=NULL;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, sd1=(struct map_session_data *)bl);
+ nullpo_retr(0, sd2=va_arg(ap,struct map_session_data *));
+
+ if( sd1->pvp_point > sd2->pvp_point )
+ sd2->pvp_rank++;
+ return 0;
+}
+/*==========================================
+ * PVP順位計算
+ *------------------------------------------
+ */
+int pc_calc_pvprank(struct map_session_data *sd)
+{
+ int old;
+ struct map_data *m;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, m=&map[sd->bl.m]);
+
+ old=sd->pvp_rank;
+
+ if( !(m->flag.pvp) )
+ return 0;
+ sd->pvp_rank=1;
+ map_foreachinarea(pc_calc_pvprank_sub,sd->bl.m,0,0,m->xs,m->ys,BL_PC,sd);
+ if(old!=sd->pvp_rank || sd->pvp_lastusers!=m->users)
+ clif_pvpset(sd,sd->pvp_rank,sd->pvp_lastusers=m->users,0);
+ return sd->pvp_rank;
+}
+/*==========================================
+ * PVP順位計算(timer)
+ *------------------------------------------
+ */
+int pc_calc_pvprank_timer(int tid,unsigned int tick,int id,int data)
+{
+ struct map_session_data *sd=NULL;
+ if(battle_config.pk_mode) // disable pvp ranking if pk_mode on [Valaris]
+ return 0;
+
+ sd=map_id2sd(id);
+ if(sd==NULL)
+ return 0;
+ sd->pvp_timer=-1;
+ if( pc_calc_pvprank(sd)>0 )
+ sd->pvp_timer=add_timer(
+ gettick()+PVP_CALCRANK_INTERVAL,
+ pc_calc_pvprank_timer,id,data);
+ return 0;
+}
+
+/*==========================================
+ * sdは結婚しているか(既婚の場合は相方のchar_idを返す)
+ *------------------------------------------
+ */
+int pc_ismarried(struct map_session_data *sd)
+{
+ if(sd == NULL)
+ return -1;
+ if(sd->status.partner_id > 0)
+ return sd->status.partner_id;
+ else
+ return 0;
+}
+/*==========================================
+ * sdがdstsdと結婚(dstsd→sdの結婚処理も同時に行う)
+ *------------------------------------------
+ */
+int pc_marriage(struct map_session_data *sd,struct map_session_data *dstsd)
+{
+ if(sd == NULL || dstsd == NULL || sd->status.partner_id > 0 || dstsd->status.partner_id > 0)
+ return -1;
+ sd->status.partner_id=dstsd->status.char_id;
+ dstsd->status.partner_id=sd->status.char_id;
+ return 0;
+}
+
+/*==========================================
+ * sdが離婚(相手はsd->status.partner_idに依る)(相手も同時に離婚・結婚指輪自動剥奪)
+ *------------------------------------------
+ */
+int pc_divorce(struct map_session_data *sd)
+{
+ struct map_session_data *p_sd=NULL;
+ if(sd == NULL || !pc_ismarried(sd))
+ return -1;
+
+ if( (p_sd=map_nick2sd(map_charid2nick(sd->status.partner_id))) !=NULL){
+ int i;
+ if(p_sd->status.partner_id != sd->status.char_id || sd->status.partner_id != p_sd->status.char_id){
+ printf("pc_divorce: Illegal partner_id sd=%d p_sd=%d\n",sd->status.partner_id,p_sd->status.partner_id);
+ return -1;
+ }
+ sd->status.partner_id=0;
+ p_sd->status.partner_id=0;
+ for(i=0;i<MAX_INVENTORY;i++)
+ if(sd->status.inventory[i].nameid == WEDDING_RING_M || sd->status.inventory[i].nameid == WEDDING_RING_F)
+ pc_delitem(sd,i,1,0);
+ for(i=0;i<MAX_INVENTORY;i++)
+ if(p_sd->status.inventory[i].nameid == WEDDING_RING_M || p_sd->status.inventory[i].nameid == WEDDING_RING_F)
+ pc_delitem(p_sd,i,1,0);
+
+ }else{
+ printf("pc_divorce: p_sd nullpo\n");
+ return -1;
+ }
+ return 0;
+}
+
+/*==========================================
+ * sdの相方のmap_session_dataを返す
+ *------------------------------------------
+ */
+struct map_session_data *pc_get_partner(struct map_session_data *sd)
+{
+ struct map_session_data *p_sd = NULL;
+ char *nick;
+ if(sd == NULL || !pc_ismarried(sd))
+ return NULL;
+
+ nick=map_charid2nick(sd->status.partner_id);
+
+ if (nick==NULL)
+ return NULL;
+
+ if((p_sd=map_nick2sd(nick)) == NULL )
+ return NULL;
+
+ return p_sd;
+}
+
+//
+// 自然回復物
+//
+/*==========================================
+ * SP回復量計算
+ *------------------------------------------
+ */
+static int natural_heal_tick,natural_heal_prev_tick,natural_heal_diff_tick;
+static int pc_spheal(struct map_session_data *sd)
+{
+ int a;
+ struct guild_castle *gc = NULL;
+
+ nullpo_retr(0, sd);
+
+ a = natural_heal_diff_tick;
+ if(pc_issit(sd)) a += a;
+ if( sd->sc_data[SC_MAGNIFICAT].timer!=-1 ) // マグニフィカート
+ a += a;
+
+ gc=guild_mapname2gc(sd->mapname); // Increased guild castle regen [Valaris]
+ if(gc) {
+ struct guild *g;
+ g=guild_search(sd->status.guild_id);
+ if(g && g->guild_id == gc->guild_id)
+ a += a;
+ } // end addition [Valaris]
+
+ return a;
+}
+
+/*==========================================
+ * HP回復量計算
+ *------------------------------------------
+ */
+static int pc_hpheal(struct map_session_data *sd)
+{
+ int a;
+ struct guild_castle *gc;
+
+ nullpo_retr(0, sd);
+
+ a = natural_heal_diff_tick;
+ if(pc_issit(sd)) a += a;
+ if( sd->sc_data[SC_MAGNIFICAT].timer!=-1 ) // Modified by RoVeRT
+ a += a;
+
+ gc=guild_mapname2gc(sd->mapname); // Increased guild castle regen [Valaris]
+ if(gc) {
+ struct guild *g;
+ g=guild_search(sd->status.guild_id);
+ if(g && g->guild_id == gc->guild_id)
+ a += a;
+ } // end addition [Valaris]
+
+ return a;
+}
+
+static int pc_natural_heal_hp(struct map_session_data *sd)
+{
+ int bhp;
+ int inc_num,bonus,skill,hp_flag;
+
+ nullpo_retr(0, sd);
+
+ if (sd->sc_data[SC_TRICKDEAD].timer != -1) // Modified by RoVeRT
+ return 0;
+
+ if(pc_checkoverhp(sd)) {
+ sd->hp_sub = sd->inchealhptick = 0;
+ return 0;
+ }
+
+ bhp=sd->status.hp;
+ hp_flag = (pc_checkskill(sd,SM_MOVINGRECOVERY) > 0 && sd->walktimer != -1);
+
+ if(sd->walktimer == -1) {
+ inc_num = pc_hpheal(sd);
+ if( sd->sc_data[SC_TENSIONRELAX].timer!=-1 ){ // テンションリラックス
+ sd->hp_sub += 2*inc_num;
+ sd->inchealhptick += 3*natural_heal_diff_tick;
+ }else{
+ sd->hp_sub += inc_num;
+ sd->inchealhptick += natural_heal_diff_tick;
+ }
+ }
+ else if(hp_flag) {
+ inc_num = pc_hpheal(sd);
+ sd->hp_sub += inc_num;
+ sd->inchealhptick = 0;
+ }
+ else {
+ sd->hp_sub = sd->inchealhptick = 0;
+ return 0;
+ }
+
+ if(sd->hp_sub >= battle_config.natural_healhp_interval) {
+ bonus = sd->nhealhp;
+ if(hp_flag) {
+ bonus >>= 2;
+ if(bonus <= 0) bonus = 1;
+ }
+ while(sd->hp_sub >= battle_config.natural_healhp_interval) {
+ sd->hp_sub -= battle_config.natural_healhp_interval;
+ if(sd->status.hp + bonus <= sd->status.max_hp)
+ sd->status.hp += bonus;
+ else {
+ sd->status.hp = sd->status.max_hp;
+ sd->hp_sub = sd->inchealhptick = 0;
+ }
+ }
+ }
+ if(bhp!=sd->status.hp)
+ clif_updatestatus(sd,SP_HP);
+
+ if(sd->nshealhp > 0) {
+ if(sd->inchealhptick >= battle_config.natural_heal_skill_interval && sd->status.hp < sd->status.max_hp) {
+ bonus = sd->nshealhp;
+ while(sd->inchealhptick >= battle_config.natural_heal_skill_interval) {
+ sd->inchealhptick -= battle_config.natural_heal_skill_interval;
+ if(sd->status.hp + bonus <= sd->status.max_hp)
+ sd->status.hp += bonus;
+ else {
+ bonus = sd->status.max_hp - sd->status.hp;
+ sd->status.hp = sd->status.max_hp;
+ sd->hp_sub = sd->inchealhptick = 0;
+ }
+ clif_heal(sd->fd,SP_HP,bonus);
+ }
+ }
+ }
+ else sd->inchealhptick = 0;
+
+ return 0;
+
+ if(sd->sc_data[SC_APPLEIDUN].timer!=-1) { // Apple of Idun
+ if(sd->inchealhptick >= 6000 && sd->status.hp < sd->status.max_hp) {
+ bonus = skill*20;
+ while(sd->inchealhptick >= 6000) {
+ sd->inchealhptick -= 6000;
+ if(sd->status.hp + bonus <= sd->status.max_hp)
+ sd->status.hp += bonus;
+ else {
+ bonus = sd->status.max_hp - sd->status.hp;
+ sd->status.hp = sd->status.max_hp;
+ sd->hp_sub = sd->inchealhptick = 0;
+ }
+ clif_heal(sd->fd,SP_HP,bonus);
+ }
+ }
+ }
+ else sd->inchealhptick = 0;
+
+ return 0;
+}
+
+static int pc_natural_heal_sp(struct map_session_data *sd)
+{
+ int bsp;
+ int inc_num,bonus;
+
+ nullpo_retr(0, sd);
+
+ if (sd->sc_data[SC_TRICKDEAD].timer != -1) // Modified by RoVeRT
+ return 0;
+
+ if(pc_checkoversp(sd)) {
+ sd->sp_sub = sd->inchealsptick = 0;
+ return 0;
+ }
+
+ bsp=sd->status.sp;
+
+ inc_num = pc_spheal(sd);
+ if(sd->sc_data[SC_EXPLOSIONSPIRITS].timer == -1)
+ sd->sp_sub += inc_num;
+ if(sd->walktimer == -1)
+ sd->inchealsptick += natural_heal_diff_tick;
+ else sd->inchealsptick = 0;
+
+ if(sd->sp_sub >= battle_config.natural_healsp_interval){
+ bonus = sd->nhealsp;;
+ while(sd->sp_sub >= battle_config.natural_healsp_interval){
+ sd->sp_sub -= battle_config.natural_healsp_interval;
+ if(sd->status.sp + bonus <= sd->status.max_sp)
+ sd->status.sp += bonus;
+ else {
+ sd->status.sp = sd->status.max_sp;
+ sd->sp_sub = sd->inchealsptick = 0;
+ }
+ }
+ }
+
+ if(bsp != sd->status.sp)
+ clif_updatestatus(sd,SP_SP);
+
+ if(sd->nshealsp > 0) {
+ if(sd->inchealsptick >= battle_config.natural_heal_skill_interval && sd->status.sp < sd->status.max_sp) {
+ struct pc_base_job s_class = pc_calc_base_job(sd->status.class);
+ if(sd->doridori_counter && s_class.job == 23)
+ bonus = sd->nshealsp*2;
+ else
+ bonus = sd->nshealsp;
+ sd->doridori_counter = 0;
+ while(sd->inchealsptick >= battle_config.natural_heal_skill_interval) {
+ sd->inchealsptick -= battle_config.natural_heal_skill_interval;
+ if(sd->status.sp + bonus <= sd->status.max_sp)
+ sd->status.sp += bonus;
+ else {
+ bonus = sd->status.max_sp - sd->status.sp;
+ sd->status.sp = sd->status.max_sp;
+ sd->sp_sub = sd->inchealsptick = 0;
+ }
+ clif_heal(sd->fd,SP_SP,bonus);
+ }
+ }
+ }
+ else sd->inchealsptick = 0;
+
+ return 0;
+}
+
+static int pc_spirit_heal_hp(struct map_session_data *sd,int level)
+{
+ int bonus_hp,interval = battle_config.natural_heal_skill_interval;
+
+ nullpo_retr(0, sd);
+
+ if(pc_checkoverhp(sd)) {
+ sd->inchealspirithptick = 0;
+ return 0;
+ }
+
+ sd->inchealspirithptick += natural_heal_diff_tick;
+
+ if(sd->weight*100/sd->max_weight >= battle_config.natural_heal_weight_rate)
+ interval += interval;
+
+ if(sd->inchealspirithptick >= interval) {
+ bonus_hp = sd->nsshealhp;
+ while(sd->inchealspirithptick >= interval) {
+ if(pc_issit(sd)) {
+ sd->inchealspirithptick -= interval;
+ if(sd->status.hp < sd->status.max_hp) {
+ if(sd->status.hp + bonus_hp <= sd->status.max_hp)
+ sd->status.hp += bonus_hp;
+ else {
+ bonus_hp = sd->status.max_hp - sd->status.hp;
+ sd->status.hp = sd->status.max_hp;
+ }
+ clif_heal(sd->fd,SP_HP,bonus_hp);
+ sd->inchealspirithptick = 0;
+ }
+ }else{
+ sd->inchealspirithptick -= natural_heal_diff_tick;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+static int pc_spirit_heal_sp(struct map_session_data *sd,int level)
+{
+ int bonus_sp,interval = battle_config.natural_heal_skill_interval;
+
+ nullpo_retr(0, sd);
+
+ if(pc_checkoversp(sd)) {
+ sd->inchealspiritsptick = 0;
+ return 0;
+ }
+
+ sd->inchealspiritsptick += natural_heal_diff_tick;
+
+ if(sd->weight*100/sd->max_weight >= battle_config.natural_heal_weight_rate)
+ interval += interval;
+
+ if(sd->inchealspiritsptick >= interval) {
+ bonus_sp = sd->nsshealsp;
+ while(sd->inchealspiritsptick >= interval) {
+ if(pc_issit(sd)) {
+ sd->inchealspiritsptick -= interval;
+ if(sd->status.sp < sd->status.max_sp) {
+ if(sd->status.sp + bonus_sp <= sd->status.max_sp)
+ sd->status.sp += bonus_sp;
+ else {
+ bonus_sp = sd->status.max_sp - sd->status.sp;
+ sd->status.sp = sd->status.max_sp;
+ }
+ clif_heal(sd->fd,SP_SP,bonus_sp);
+ sd->inchealspiritsptick = 0;
+ }
+ }else{
+ sd->inchealspiritsptick -= natural_heal_diff_tick;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * HP/SP 自然回復 各クライアント
+ *------------------------------------------
+ */
+
+static int pc_natural_heal_sub(struct map_session_data *sd,va_list ap) {
+ int skill;
+
+ nullpo_retr(0, sd);
+
+// -- moonsoul (if conditions below altered to disallow natural healing if under berserk status)
+ if ((battle_config.natural_heal_weight_rate > 100 || sd->weight*100/sd->max_weight < battle_config.natural_heal_weight_rate) &&
+ !pc_isdead(sd) &&
+ !pc_ishiding(sd) &&
+ sd->sc_data[SC_POISON].timer == -1
+ ) {
+ pc_natural_heal_hp(sd);
+ if( sd->sc_data && sd->sc_data[SC_EXTREMITYFIST].timer == -1 && //阿修羅状態ではSPが回復しない
+ sd->sc_data[SC_DANCING].timer == -1 && //ダンス状態ではSPが回復しない
+ sd->sc_data[SC_BERSERK].timer == -1 //バーサーク状態ではSPが回復しない
+ )
+ pc_natural_heal_sp(sd);
+ } else {
+ sd->hp_sub = sd->inchealhptick = 0;
+ sd->sp_sub = sd->inchealsptick = 0;
+ }
+ if((skill = pc_checkskill(sd,MO_SPIRITSRECOVERY)) > 0 && !pc_ishiding(sd) && sd->sc_data[SC_POISON].timer == -1 && sd->sc_data[SC_BERSERK].timer == -1){
+ pc_spirit_heal_hp(sd,skill);
+ pc_spirit_heal_sp(sd,skill);
+ }
+ else {
+ sd->inchealspirithptick = 0;
+ sd->inchealspiritsptick = 0;
+ }
+ return 0;
+}
+
+/*==========================================
+ * HP/SP自然回復 (interval timer関数)
+ *------------------------------------------
+ */
+int pc_natural_heal(int tid,unsigned int tick,int id,int data)
+{
+ natural_heal_tick = tick;
+ natural_heal_diff_tick = DIFF_TICK(natural_heal_tick,natural_heal_prev_tick);
+ clif_foreachclient(pc_natural_heal_sub);
+
+ natural_heal_prev_tick = tick;
+ return 0;
+}
+
+/*==========================================
+ * セーブポイントの保存
+ *------------------------------------------
+ */
+int pc_setsavepoint(struct map_session_data *sd,char *mapname,int x,int y)
+{
+ nullpo_retr(0, sd);
+
+ strncpy(sd->status.save_point.map,mapname,24);
+ sd->status.save_point.x = x;
+ sd->status.save_point.y = y;
+
+ return 0;
+}
+
+/*==========================================
+ * 自動セーブ 各クライアント
+ *------------------------------------------
+ */
+static int last_save_fd,save_flag;
+static int pc_autosave_sub(struct map_session_data *sd,va_list ap)
+{
+ nullpo_retr(0, sd);
+
+ if(save_flag==0 && sd->fd>last_save_fd){
+ struct guild_castle *gc=NULL;
+ int i;
+// if(battle_config.save_log)
+// printf("autosave %d\n",sd->fd);
+ // pet
+ if(sd->status.pet_id > 0 && sd->pd)
+ intif_save_petdata(sd->status.account_id,&sd->pet);
+ pc_makesavestatus(sd);
+ chrif_save(sd);
+ storage_storage_save(sd);
+
+ for(i=0;i<MAX_GUILDCASTLE;i++){
+ gc=guild_castle_search(i);
+ if(!gc) continue;
+ if(gc->visibleG0==1) guild_castledatasave(gc->castle_id,18,gc->Ghp0);
+ if(gc->visibleG1==1) guild_castledatasave(gc->castle_id,19,gc->Ghp1);
+ if(gc->visibleG2==1) guild_castledatasave(gc->castle_id,20,gc->Ghp2);
+ if(gc->visibleG3==1) guild_castledatasave(gc->castle_id,21,gc->Ghp3);
+ if(gc->visibleG4==1) guild_castledatasave(gc->castle_id,22,gc->Ghp4);
+ if(gc->visibleG5==1) guild_castledatasave(gc->castle_id,23,gc->Ghp5);
+ if(gc->visibleG6==1) guild_castledatasave(gc->castle_id,24,gc->Ghp6);
+ if(gc->visibleG7==1) guild_castledatasave(gc->castle_id,25,gc->Ghp7);
+ }
+
+ save_flag=1;
+ last_save_fd = sd->fd;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 自動セーブ (timer関数)
+ *------------------------------------------
+ */
+int pc_autosave(int tid,unsigned int tick,int id,int data)
+{
+ int interval;
+
+ save_flag=0;
+ clif_foreachclient(pc_autosave_sub);
+ if(save_flag==0)
+ last_save_fd=0;
+
+ interval = autosave_interval/(clif_countusers()+1);
+ if(interval <= 0)
+ interval = 1;
+ add_timer(gettick()+interval,pc_autosave,0,0);
+
+ return 0;
+}
+
+int pc_read_gm_account(int fd)
+{
+#ifdef TXT_ONLY
+ int i = 0;
+#endif
+ if (gm_account != NULL)
+ free(gm_account);
+ GM_num = 0;
+#ifdef TXT_ONLY
+ gm_account = calloc(sizeof(struct gm_account) * ((RFIFOW(fd,2) - 4) / 5), 1);
+ for (i = 4; i < RFIFOW(fd,2); i = i + 5) {
+ gm_account[GM_num].account_id = RFIFOL(fd,i);
+ gm_account[GM_num].level = (int)RFIFOB(fd,i+4);
+ //printf("GM account: %d -> level %d\n", gm_account[GM_num].account_id, gm_account[GM_num].level);
+ GM_num++;
+ }
+#else
+ sprintf (tmp_lsql, "SELECT `%s`,`%s` FROM `%s` WHERE `%s`>='%d'",gm_db_account_id,gm_db_level,gm_db,gm_db_level,lowest_gm_level);
+ if(mysql_query(&lmysql_handle, tmp_lsql) ) {
+ printf("DB server Error (select %s to Memory)- %s\n",login_db,mysql_error(&lmysql_handle) );
+ }
+ lsql_res = mysql_store_result(&lmysql_handle);
+ if (lsql_res) {
+ gm_account = calloc(sizeof(struct gm_account) * mysql_num_rows(lsql_res), 1);
+ while ((lsql_row = mysql_fetch_row(lsql_res))) {
+ gm_account[GM_num].account_id = atoi(lsql_row[0]);
+ gm_account[GM_num].level = atoi(lsql_row[1]);
+ printf("GM account: %d -> level %d\n", gm_account[GM_num].account_id, gm_account[GM_num].level);
+ GM_num++;
+ }
+ }
+
+ mysql_free_result(lsql_res);
+#endif /* TXT_ONLY */
+ return GM_num;
+}
+
+/*==========================================
+ * timer to do the day
+ *------------------------------------------
+ */
+int map_day_timer(int tid, unsigned int tick, int id, int data) { // by [yor]
+ struct map_session_data *pl_sd = NULL;
+ int i;
+ char tmpstr[1024];
+
+ if (battle_config.day_duration > 0) { // if we want a day
+ if (night_flag != 0) {
+ strcpy(tmpstr, msg_txt(502)); // The day has arrived!
+ night_flag = 0; // 0=day, 1=night [Yor]
+ for(i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
+ pl_sd->opt2 &= ~STATE_BLIND;
+ clif_changeoption(&pl_sd->bl);
+ clif_wis_message(pl_sd->fd, wisp_server_name, tmpstr, strlen(tmpstr)+1);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * timer to do the night
+ *------------------------------------------
+ */
+int map_night_timer(int tid, unsigned int tick, int id, int data) { // by [yor]
+ struct map_session_data *pl_sd = NULL;
+ int i;
+ char tmpstr[1024];
+
+ if (battle_config.night_duration > 0) { // if we want a night
+ if (night_flag == 0) {
+ strcpy(tmpstr, msg_txt(503)); // The night has fallen...
+ night_flag = 1; // 0=day, 1=night [Yor]
+ for(i = 0; i < fd_max; i++) {
+ if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
+ pl_sd->opt2 |= STATE_BLIND;
+ clif_changeoption(&pl_sd->bl);
+ clif_wis_message(pl_sd->fd, wisp_server_name, tmpstr, strlen(tmpstr)+1);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+void pc_setstand(struct map_session_data *sd){
+ nullpo_retv(sd);
+
+ if(sd->sc_data && sd->sc_data[SC_TENSIONRELAX].timer!=-1)
+ skill_status_change_end(&sd->bl,SC_TENSIONRELAX,-1);
+
+ sd->state.dead_sit = 0;
+}
+
+//
+// 初期化物
+//
+/*==========================================
+ * 設定ファイル読み込む
+ * exp.txt 必要経験値
+ * job_db1.txt 重量,hp,sp,攻撃速度
+ * job_db2.txt job能力値ボーナス
+ * skill_tree.txt 各職毎のスキルツリー
+ * attr_fix.txt 属性修正テーブル
+ * size_fix.txt サイズ補正テーブル
+ * refine_db.txt 精錬データテーブル
+ *------------------------------------------
+ */
+int pc_readdb(void)
+{
+ int i,j,k;
+ FILE *fp;
+ char line[1024],*p;
+
+ // 必要経験値読み込み
+
+ fp=fopen("db/exp.txt","r");
+ if(fp==NULL){
+ printf("can't read db/exp.txt\n");
+ return 1;
+ }
+ i=0;
+ while(fgets(line, sizeof(line)-1, fp)){
+ int bn,b1,b2,b3,b4,b5,b6,jn,j1,j2,j3,j4,j5,j6;
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ if(sscanf(line,"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",&bn,&b1,&b2,&b3,&b4,&b5,&b6,&jn,&j1,&j2,&j3,&j4,&j5,&j6)!=14)
+ continue;
+ exp_table[0][i]=bn;
+ exp_table[1][i]=b1;
+ exp_table[2][i]=b2;
+ exp_table[3][i]=b3;
+ exp_table[4][i]=b4;
+ exp_table[5][i]=b5;
+ exp_table[6][i]=b6;
+ exp_table[7][i]=jn;
+ exp_table[8][i]=j1;
+ exp_table[9][i]=j2;
+ exp_table[10][i]=j3;
+ exp_table[11][i]=j4;
+ exp_table[12][i]=j5;
+ exp_table[13][i]=j6;
+ i++;
+ if(i >= battle_config.maximum_level)
+ break;
+ }
+ fclose(fp);
+ printf("read db/exp.txt done\n");
+
+ // JOB補正数値1
+ fp=fopen("db/job_db1.txt","r");
+ if(fp==NULL){
+ printf("can't read db/job_db1.txt\n");
+ return 1;
+ }
+ i=0;
+ while(fgets(line, sizeof(line)-1, fp)){
+ char *split[50];
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ for(j=0,p=line;j<21 && p;j++){
+ split[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+ if(j<21)
+ continue;
+ max_weight_base[i]=atoi(split[0]);
+ hp_coefficient[i]=atoi(split[1]);
+ hp_coefficient2[i]=atoi(split[2]);
+ sp_coefficient[i]=atoi(split[3]);
+ for(j=0;j<17;j++)
+ aspd_base[i][j]=atoi(split[j+4]);
+ i++;
+// -- moonsoul (below two lines added to accommodate high numbered new class ids)
+ if(i==24)
+ i=4001;
+ if(i==MAX_PC_CLASS)
+ break;
+ }
+ fclose(fp);
+ printf("read db/job_db1.txt done\n");
+
+ // JOBボーナス
+ fp=fopen("db/job_db2.txt","r");
+ if(fp==NULL){
+ printf("can't read db/job_db2.txt\n");
+ return 1;
+ }
+ i=0;
+ while(fgets(line, sizeof(line)-1, fp)){
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ for(j=0,p=line;j<MAX_LEVEL && p;j++){
+ if(sscanf(p,"%d",&k)==0)
+ break;
+ job_bonus[0][i][j]=k;
+ job_bonus[2][i][j]=k; //養子職のボーナスは分からないので仮
+ p=strchr(p,',');
+ if(p) p++;
+ }
+ i++;
+// -- moonsoul (below two lines added to accommodate high numbered new class ids)
+ if(i==24)
+ i=4001;
+ if(i==MAX_PC_CLASS)
+ break;
+ }
+ fclose(fp);
+ printf("read db/job_db2.txt done\n");
+
+ // JOBボーナス2 転生職用
+ fp=fopen("db/job_db2-2.txt","r");
+ if(fp==NULL){
+ printf("can't read db/job_db2-2.txt\n");
+ return 1;
+ }
+ i=0;
+ while(fgets(line, sizeof(line)-1, fp)){
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ for(j=0,p=line;j<MAX_LEVEL && p;j++){
+ if(sscanf(p,"%d",&k)==0)
+ break;
+ job_bonus[1][i][j]=k;
+ p=strchr(p,',');
+ if(p) p++;
+ }
+ i++;
+ if(i==MAX_PC_CLASS)
+ break;
+ }
+ fclose(fp);
+ printf("read db/job_db2-2.txt done\n");
+
+ // スキルツリー
+ memset(skill_tree,0,sizeof(skill_tree));
+ fp=fopen("db/skill_tree.txt","r");
+ if(fp==NULL){
+ printf("can't read db/skill_tree.txt\n");
+ return 1;
+ }
+ while(fgets(line, sizeof(line)-1, fp)){
+ char *split[50];
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ for(j=0,p=line;j<13 && p;j++){
+ split[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+ if(j<13)
+ continue;
+ i=atoi(split[0]);
+ for(j=0;skill_tree[0][i][j].id;j++);
+ skill_tree[0][i][j].id=atoi(split[1]);
+ skill_tree[0][i][j].max=atoi(split[2]);
+ skill_tree[2][i][j].id=atoi(split[1]); //養子職は良く分からないので暫定
+ skill_tree[2][i][j].max=atoi(split[2]); //養子職は良く分からないので暫定
+ for(k=0;k<5;k++){
+ skill_tree[0][i][j].need[k].id=atoi(split[k*2+3]);
+ skill_tree[0][i][j].need[k].lv=atoi(split[k*2+4]);
+ skill_tree[2][i][j].need[k].id=atoi(split[k*2+3]); //養子職は良く分からないので暫定
+ skill_tree[2][i][j].need[k].lv=atoi(split[k*2+4]); //養子職は良く分からないので暫定
+ }
+ }
+ fclose(fp);
+ printf("read db/skill_tree.txt done\n");
+
+ // 属性修正テーブル
+ for(i=0;i<4;i++)
+ for(j=0;j<10;j++)
+ for(k=0;k<10;k++)
+ attr_fix_table[i][j][k]=100;
+ fp=fopen("db/attr_fix.txt","r");
+ if(fp==NULL){
+ printf("can't read db/attr_fix.txt\n");
+ return 1;
+ }
+ while(fgets(line, sizeof(line)-1, fp)){
+ char *split[10];
+ int lv,n;
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ for(j=0,p=line;j<3 && p;j++){
+ split[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+ lv=atoi(split[0]);
+ n=atoi(split[1]);
+// printf("%d %d\n",lv,n);
+
+ for(i=0;i<n;){
+ if( !fgets(line, sizeof(line)-1, fp) )
+ break;
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+
+ for(j=0,p=line;j<n && p;j++){
+ while(*p==32 && *p>0)
+ p++;
+ attr_fix_table[lv-1][i][j]=atoi(p);
+ if(battle_config.attr_recover == 0 && attr_fix_table[lv-1][i][j] < 0)
+ attr_fix_table[lv-1][i][j] = 0;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+
+ i++;
+ }
+ }
+ fclose(fp);
+ printf("read db/attr_fix.txt done\n");
+
+ // サイズ補正テーブル
+ for(i=0;i<3;i++)
+ for(j=0;j<20;j++)
+ atkmods[i][j]=100;
+ fp=fopen("db/size_fix.txt","r");
+ if(fp==NULL){
+ printf("can't read db/size_fix.txt\n");
+ return 1;
+ }
+ i=0;
+ while(fgets(line, sizeof(line)-1, fp)){
+ char *split[20];
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ if(atoi(line)<=0)
+ continue;
+ memset(split,0,sizeof(split));
+ for(j=0,p=line;j<20 && p;j++){
+ split[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+ for(j=0;j<20 && split[j];j++)
+ atkmods[i][j]=atoi(split[j]);
+ i++;
+ }
+ fclose(fp);
+ printf("read db/size_fix.txt done\n");
+
+ // 精錬データテーブル
+ for(i=0;i<5;i++){
+ for(j=0;j<10;j++)
+ percentrefinery[i][j]=100;
+ refinebonus[i][0]=0;
+ refinebonus[i][1]=0;
+ refinebonus[i][2]=10;
+ }
+ fp=fopen("db/refine_db.txt","r");
+ if(fp==NULL){
+ printf("can't read db/refine_db.txt\n");
+ return 1;
+ }
+ i=0;
+ while(fgets(line, sizeof(line)-1, fp)){
+ char *split[16];
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ if(atoi(line)<=0)
+ continue;
+ memset(split,0,sizeof(split));
+ for(j=0,p=line;j<16 && p;j++){
+ split[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+ refinebonus[i][0]=atoi(split[0]); // 精錬ボーナス
+ refinebonus[i][1]=atoi(split[1]); // 過剰精錬ボーナス
+ refinebonus[i][2]=atoi(split[2]); // 安全精錬限界
+ for(j=0;j<10 && split[j];j++)
+ percentrefinery[i][j]=atoi(split[j+3]);
+ i++;
+ }
+ fclose(fp); //Lupus. close this file!!!
+ printf("read db/refine_db.txt done\n");
+
+ return 0;
+}
+
+static int pc_calc_sigma(void)
+{
+ int i,j,k;
+
+ for(i=0;i<MAX_PC_CLASS;i++) {
+ memset(hp_sigma_val[i],0,sizeof(hp_sigma_val[i]));
+ for(k=0,j=2;j<=MAX_LEVEL;j++) {
+ k += hp_coefficient[i]*j + 50;
+ k -= k%100;
+ hp_sigma_val[i][j-1] = k;
+ }
+ }
+ return 0;
+}
+
+static void pc_statpointdb(void)
+{
+ char * buf_stat;
+ int i=0,j=0,k=0,l=0, end = 0;
+
+ FILE *stp;
+
+ stp=fopen("db/statpoint.txt","r");
+
+ if(stp==NULL){
+ printf("can't read db/statpoint.txt\n");
+ return;
+ }
+
+ fseek(stp, 0, SEEK_END);
+ end = ftell(stp);
+ rewind(stp);
+
+ buf_stat = (char *) malloc (end + 1);
+ l = fread(buf_stat,1,end,stp);
+ fclose(stp);
+ printf("read db/statpoint.txt done (size=%d)\n",l);
+
+ for(i=0;i<255;i++) {
+ j=0;
+ while (*(buf_stat+k)!='\n') {
+ statp[i][j]=*(buf_stat+k);
+ j++;k++;
+ }
+ statp[i][j+1]='\0';
+ k++;
+ }
+
+ free(buf_stat);
+}
+
+/*==========================================
+ * pc関 係初期化
+ *------------------------------------------
+ */
+int do_init_pc(void) {
+ pc_readdb();
+ pc_statpointdb();
+ pc_calc_sigma();
+
+// gm_account_db = numdb_init();
+
+ add_timer_func_list(pc_walk, "pc_walk");
+ add_timer_func_list(pc_attack_timer, "pc_attack_timer");
+ add_timer_func_list(pc_natural_heal, "pc_natural_heal");
+ add_timer_func_list(pc_invincible_timer, "pc_invincible_timer");
+ add_timer_func_list(pc_eventtimer, "pc_eventtimer");
+ add_timer_func_list(pc_calc_pvprank_timer, "pc_calc_pvprank_timer");
+ add_timer_func_list(pc_autosave, "pc_autosave");
+ add_timer_func_list(pc_spiritball_timer, "pc_spiritball_timer");
+ add_timer_interval((natural_heal_prev_tick = gettick() + NATURAL_HEAL_INTERVAL), pc_natural_heal, 0, 0, NATURAL_HEAL_INTERVAL);
+ add_timer(gettick() + autosave_interval, pc_autosave, 0, 0);
+
+#ifndef TXT_ONLY
+ pc_read_gm_account(0);
+#endif /* not TXT_ONLY */
+
+ // add night/day timer (by [yor])
+ add_timer_func_list(map_day_timer, "map_day_timer"); // by [yor]
+ add_timer_func_list(map_night_timer, "map_night_timer"); // by [yor]
+ {
+ int day_duration = battle_config.day_duration;
+ int night_duration = battle_config.night_duration;
+ if (day_duration < 60000)
+ day_duration = 60000;
+ if (night_duration < 60000)
+ night_duration = 60000;
+ if (battle_config.night_at_start == 0) {
+ night_flag = 0; // 0=day, 1=night [Yor]
+ day_timer_tid = add_timer_interval(gettick() + day_duration + night_duration, map_day_timer, 0, 0, day_duration + night_duration);
+ night_timer_tid = add_timer_interval(gettick() + day_duration, map_night_timer, 0, 0, day_duration + night_duration);
+ } else {
+ night_flag = 1; // 0=day, 1=night [Yor]
+ day_timer_tid = add_timer_interval(gettick() + night_duration, map_day_timer, 0, 0, day_duration + night_duration);
+ night_timer_tid = add_timer_interval(gettick() + day_duration + night_duration, map_night_timer, 0, 0, day_duration + night_duration);
+ }
+ }
+
+ return 0;
+}
diff --git a/src/map/pc.h b/src/map/pc.h
new file mode 100644
index 000000000..befa690fd
--- /dev/null
+++ b/src/map/pc.h
@@ -0,0 +1,186 @@
+// $Id: pc.h,v 1.4 2004/09/25 05:32:18 MouseJstr Exp $
+
+#ifndef _PC_H_
+#define _PC_H_
+
+#include "map.h"
+
+#define OPTION_MASK 0xd7b8
+#define CART_MASK 0x788
+
+#define pc_setdead(sd) ((sd)->state.dead_sit = 1)
+#define pc_setsit(sd) ((sd)->state.dead_sit = 2)
+//#define pc_setstand(sd) ((sd)->state.dead_sit = 0)
+#define pc_isdead(sd) ((sd)->state.dead_sit == 1)
+#define pc_issit(sd) ((sd)->state.dead_sit == 2)
+#define pc_setdir(sd,b,h) ((sd)->dir = (b) ,(sd)->head_dir = (h) )
+#define pc_setchatid(sd,n) ((sd)->chatID = n)
+#define pc_ishiding(sd) ((sd)->status.option&0x4006)
+#define pc_iscarton(sd) ((sd)->status.option&CART_MASK)
+#define pc_isfalcon(sd) ((sd)->status.option&0x0010)
+#define pc_isriding(sd) ((sd)->status.option&0x0020)
+#define pc_isinvisible(sd) ((sd)->status.option&0x0040)
+#define pc_is50overweight(sd) (sd->weight*2 >= sd->max_weight)
+#define pc_is90overweight(sd) (sd->weight*10 >= sd->max_weight*9)
+
+int pc_isGM(struct map_session_data *sd);
+int pc_iskiller(struct map_session_data *src, struct map_session_data *target); // [MouseJstr]
+int pc_getrefinebonus(int lv,int type);
+
+int pc_counttargeted(struct map_session_data *sd,struct block_list *src,int target_lv);
+int pc_setrestartvalue(struct map_session_data *sd,int type);
+int pc_makesavestatus(struct map_session_data *);
+int pc_setnewpc(struct map_session_data*,int,int,int,int,int,int);
+int pc_authok(int, int, time_t, struct mmo_charstatus *);
+int pc_authfail(int);
+
+int pc_isequip(struct map_session_data *sd,int n);
+int pc_equippoint(struct map_session_data *sd,int n);
+
+int pc_breakweapon(struct map_session_data *sd); // weapon breaking [Valaris]
+int pc_breakarmor(struct map_session_data *sd); // armor breaking [Valaris]
+
+int pc_checkskill(struct map_session_data *sd,int skill_id);
+int pc_checkallowskill(struct map_session_data *sd);
+int pc_checkequip(struct map_session_data *sd,int pos);
+
+int pc_checkoverhp(struct map_session_data*);
+int pc_checkoversp(struct map_session_data*);
+
+int pc_can_reach(struct map_session_data*,int,int);
+int pc_walktoxy(struct map_session_data*,int,int);
+int pc_stop_walking(struct map_session_data*,int);
+int pc_movepos(struct map_session_data*,int,int);
+int pc_setpos(struct map_session_data*,char*,int,int,int);
+int pc_setsavepoint(struct map_session_data*,char*,int,int);
+int pc_randomwarp(struct map_session_data *sd,int type);
+int pc_memo(struct map_session_data *sd,int i);
+
+int pc_checkadditem(struct map_session_data*,int,int);
+int pc_inventoryblank(struct map_session_data*);
+int pc_search_inventory(struct map_session_data *sd,int item_id);
+int pc_payzeny(struct map_session_data*,int);
+int pc_additem(struct map_session_data*,struct item*,int);
+int pc_getzeny(struct map_session_data*,int);
+int pc_delitem(struct map_session_data*,int,int,int);
+int pc_checkitem(struct map_session_data*);
+
+int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amount);
+int pc_cart_delitem(struct map_session_data *sd,int n,int amount,int type);
+int pc_putitemtocart(struct map_session_data *sd,int idx,int amount);
+int pc_getitemfromcart(struct map_session_data *sd,int idx,int amount);
+int pc_cartitem_amount(struct map_session_data *sd,int idx,int amount);
+
+int pc_takeitem(struct map_session_data*,struct flooritem_data*);
+int pc_dropitem(struct map_session_data*,int,int);
+
+int pc_checkweighticon(struct map_session_data *sd);
+
+int pc_calcstatus(struct map_session_data*,int);
+int pc_bonus(struct map_session_data*,int,int);
+int pc_bonus2(struct map_session_data *sd,int,int,int);
+int pc_bonus3(struct map_session_data *sd,int,int,int,int);
+int pc_skill(struct map_session_data*,int,int,int);
+
+int pc_insert_card(struct map_session_data *sd,int idx_card,int idx_equip);
+
+int pc_item_identify(struct map_session_data *sd,int idx);
+int pc_steal_item(struct map_session_data *sd,struct block_list *bl);
+int pc_steal_coin(struct map_session_data *sd,struct block_list *bl);
+
+int pc_modifybuyvalue(struct map_session_data*,int);
+int pc_modifysellvalue(struct map_session_data*,int);
+
+int pc_attack(struct map_session_data*,int,int);
+int pc_stopattack(struct map_session_data*);
+
+int pc_follow(struct map_session_data*, int); // [MouseJstr]
+
+int pc_checkbaselevelup(struct map_session_data *sd);
+int pc_checkjoblevelup(struct map_session_data *sd);
+int pc_gainexp(struct map_session_data*,int,int);
+int pc_nextbaseexp(struct map_session_data *);
+int pc_nextbaseafter(struct map_session_data *); // [Valaris]
+int pc_nextjobexp(struct map_session_data *);
+int pc_nextjobafter(struct map_session_data *); // [Valaris]
+int pc_need_status_point(struct map_session_data *,int);
+int pc_statusup(struct map_session_data*,int);
+int pc_statusup2(struct map_session_data*,int,int);
+int pc_skillup(struct map_session_data*,int);
+int pc_allskillup(struct map_session_data*);
+int pc_resetlvl(struct map_session_data*,int type);
+int pc_resetstate(struct map_session_data*);
+int pc_resetskill(struct map_session_data*);
+int pc_equipitem(struct map_session_data*,int,int);
+int pc_unequipitem(struct map_session_data*,int,int);
+int pc_checkitem(struct map_session_data*);
+int pc_useitem(struct map_session_data*,int);
+
+int pc_damage(struct block_list *,struct map_session_data*,int);
+int pc_heal(struct map_session_data *,int,int);
+int pc_itemheal(struct map_session_data *sd,int hp,int sp);
+int pc_percentheal(struct map_session_data *sd,int,int);
+int pc_jobchange(struct map_session_data *,int, int);
+int pc_setoption(struct map_session_data *,int);
+int pc_setcart(struct map_session_data *sd,int type);
+int pc_setfalcon(struct map_session_data *sd);
+int pc_setriding(struct map_session_data *sd);
+int pc_changelook(struct map_session_data *,int,int);
+int pc_equiplookall(struct map_session_data *sd);
+
+int pc_readparam(struct map_session_data*,int);
+int pc_setparam(struct map_session_data*,int,int);
+int pc_readreg(struct map_session_data*,int);
+int pc_setreg(struct map_session_data*,int,int);
+char *pc_readregstr(struct map_session_data *sd,int reg);
+int pc_setregstr(struct map_session_data *sd,int reg,char *str);
+int pc_readglobalreg(struct map_session_data*,char*);
+int pc_setglobalreg(struct map_session_data*,char*,int);
+int pc_readaccountreg(struct map_session_data*,char*);
+int pc_setaccountreg(struct map_session_data*,char*,int);
+int pc_readaccountreg2(struct map_session_data*,char*);
+int pc_setaccountreg2(struct map_session_data*,char*,int);
+int pc_percentrefinery(struct map_session_data *sd,struct item *item);
+
+int pc_addeventtimer(struct map_session_data *sd,int tick,const char *name);
+int pc_deleventtimer(struct map_session_data *sd,const char *name);
+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,int data);
+
+int pc_ismarried(struct map_session_data *sd);
+int pc_marriage(struct map_session_data *sd,struct map_session_data *dstsd);
+int pc_divorce(struct map_session_data *sd);
+struct map_session_data *pc_get_partner(struct map_session_data *sd);
+int pc_set_gm_level(int account_id, int level);
+void pc_setstand(struct map_session_data *sd);
+
+
+struct pc_base_job{
+ int job; //職業、ただし転生職や養子職の場合は元の職業を返す(廃プリ→プリ)
+ int type; //ノビ 0, 一次職 1, 二次職 2, スパノビ 3
+ int upper; //通常 0, 転生 1, 養子 2
+};
+
+struct pc_base_job pc_calc_base_job(int b_class);//転生や養子職の元の職業を返す
+
+int pc_read_gm_account(int fd);
+int pc_setinvincibletimer(struct map_session_data *sd,int);
+int pc_delinvincibletimer(struct map_session_data *sd);
+int pc_addspiritball(struct map_session_data *sd,int,int);
+int pc_delspiritball(struct map_session_data *sd,int,int);
+
+int do_init_pc(void);
+
+enum {ADDITEM_EXIST,ADDITEM_NEW,ADDITEM_OVERAMOUNT};
+
+// timer for night.day
+int day_timer_tid;
+int night_timer_tid;
+int map_day_timer(int,unsigned int,int,int); // by [yor]
+int map_night_timer(int,unsigned int,int,int); // by [yor]
+
+#endif
+
diff --git a/src/map/pet.c b/src/map/pet.c
new file mode 100644
index 000000000..8bc17003a
--- /dev/null
+++ b/src/map/pet.c
@@ -0,0 +1,1651 @@
+// $Id: pet.c,v 1.4 2004/09/25 05:32:18 MouseJstr Exp $
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db.h"
+#include "timer.h"
+#include "socket.h"
+#include "nullpo.h"
+#include "malloc.h"
+#include "pc.h"
+#include "map.h"
+#include "intif.h"
+#include "clif.h"
+#include "chrif.h"
+#include "pet.h"
+#include "itemdb.h"
+#include "battle.h"
+#include "mob.h"
+#include "npc.h"
+#include "script.h"
+#include "skill.h"
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+#define MIN_PETTHINKTIME 100
+
+struct pet_db pet_db[MAX_PET_DB];
+
+static int dirx[8]={0,-1,-1,-1,0,1,1,1};
+static int diry[8]={1,1,0,-1,-1,-1,0,1};
+
+static int pet_timer(int tid,unsigned int tick,int id,int data);
+static int pet_walktoxy_sub(struct pet_data *pd);
+
+static int distance(int x0,int y0,int x1,int y1)
+{
+ int dx,dy;
+
+ dx=abs(x0-x1);
+ dy=abs(y0-y1);
+ return dx>dy ? dx : dy;
+}
+
+static int calc_next_walk_step(struct pet_data *pd)
+{
+ nullpo_retr(0, pd);
+
+ if(pd->walkpath.path_pos>=pd->walkpath.path_len)
+ return -1;
+ if(pd->walkpath.path[pd->walkpath.path_pos]&1)
+ return pd->speed*14/10;
+ return pd->speed;
+}
+
+static int pet_performance_val(struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+
+ if(sd->pet.intimate > 900)
+ return (sd->petDB->s_perfor > 0)? 4:3;
+ else if(sd->pet.intimate > 750)
+ return 2;
+ else
+ return 1;
+}
+
+int pet_hungry_val(struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+
+ if(sd->pet.hungry > 90)
+ return 4;
+ else if(sd->pet.hungry > 75)
+ return 3;
+ else if(sd->pet.hungry > 25)
+ return 2;
+ else if(sd->pet.hungry > 10)
+ return 1;
+ else
+ return 0;
+}
+
+static int pet_can_reach(struct pet_data *pd,int x,int y)
+{
+ struct walkpath_data wpd;
+
+ nullpo_retr(0, pd);
+
+ if( pd->bl.x==x && pd->bl.y==y ) // 同じマス
+ return 1;
+
+ // 障害物判定
+ wpd.path_len=0;
+ wpd.path_pos=0;
+ wpd.path_half=0;
+ return (path_search(&wpd,pd->bl.m,pd->bl.x,pd->bl.y,x,y,0)!=-1)?1:0;
+}
+
+static int pet_calc_pos(struct pet_data *pd,int tx,int ty,int dir)
+{
+ int x,y,dx,dy;
+ int i,j=0,k;
+
+ nullpo_retr(0, pd);
+
+ pd->to_x = tx;
+ pd->to_y = ty;
+
+ if(dir >= 0 && dir < 8) {
+ dx = -dirx[dir]*2;
+ dy = -diry[dir]*2;
+ x = tx + dx;
+ y = ty + dy;
+ if(!(j=pet_can_reach(pd,x,y))) {
+ if(dx > 0) x--;
+ else if(dx < 0) x++;
+ if(dy > 0) y--;
+ else if(dy < 0) y++;
+ if(!(j=pet_can_reach(pd,x,y))) {
+ for(i=0;i<12;i++) {
+ k = rand()%8;
+ dx = -dirx[k]*2;
+ dy = -diry[k]*2;
+ x = tx + dx;
+ y = ty + dy;
+ if((j=pet_can_reach(pd,x,y)))
+ break;
+ else {
+ if(dx > 0) x--;
+ else if(dx < 0) x++;
+ if(dy > 0) y--;
+ else if(dy < 0) y++;
+ if((j=pet_can_reach(pd,x,y)))
+ break;
+ }
+ }
+ if(!j) {
+ x = tx;
+ y = ty;
+ if(!pet_can_reach(pd,x,y))
+ return 1;
+ }
+ }
+ }
+ }
+ else
+ return 1;
+
+ pd->to_x = x;
+ pd->to_y = y;
+ return 0;
+}
+
+static int pet_attack(struct pet_data *pd,unsigned int tick,int data)
+{
+ struct mob_data *md;
+ int mode,race,range;
+
+ nullpo_retr(0, pd);
+
+ pd->state.state=MS_IDLE;
+
+ md=(struct mob_data *)map_id2bl(pd->target_id);
+ if(md == NULL || md->bl.type != BL_MOB || pd->bl.m != md->bl.m || md->bl.prev == NULL ||
+ distance(pd->bl.x,pd->bl.y,md->bl.x,md->bl.y) > 13) {
+ pd->target_id=0;
+ return 0;
+ }
+
+ mode=mob_db[pd->class].mode;
+ race=mob_db[pd->class].race;
+ if(mob_db[pd->class].mexp <= 0 && !(mode&0x20) && (md->option & 0x06 && race != 4 && race != 6) ) {
+ pd->target_id=0;
+ return 0;
+ }
+
+ range = mob_db[pd->class].range + 1;
+ if(distance(pd->bl.x,pd->bl.y,md->bl.x,md->bl.y) > range)
+ return 0;
+ if(battle_config.monster_attack_direction_change)
+ pd->dir=map_calc_dir(&pd->bl, md->bl.x,md->bl.y );
+
+ clif_fixpetpos(pd);
+
+ pd->target_lv = battle_weapon_attack(&pd->bl,&md->bl,tick,0);
+
+ pd->attackabletime = tick + battle_get_adelay(&pd->bl);
+
+ pd->timer=add_timer(pd->attackabletime,pet_timer,pd->bl.id,0);
+ pd->state.state=MS_ATTACK;
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static int pet_walk(struct pet_data *pd,unsigned int tick,int data)
+{
+ int moveblock;
+ int i,ctype;
+ int x,y,dx,dy;
+
+ nullpo_retr(0, pd);
+
+ pd->state.state=MS_IDLE;
+ if(pd->walkpath.path_pos >= pd->walkpath.path_len || pd->walkpath.path_pos != data)
+ return 0;
+
+ pd->walkpath.path_half ^= 1;
+ if(pd->walkpath.path_half==0){
+ pd->walkpath.path_pos++;
+ if(pd->state.change_walk_target){
+ pet_walktoxy_sub(pd);
+ return 0;
+ }
+ }
+ else {
+ if(pd->walkpath.path[pd->walkpath.path_pos] >= 8)
+ return 1;
+
+ x = pd->bl.x;
+ y = pd->bl.y;
+/* ctype = map_getcell(pd->bl.m,x,y);
+ if(ctype == 1 || ctype == 5) {
+ pet_stop_walking(pd,1);
+ return 0;
+ }*/
+ pd->dir=pd->walkpath.path[pd->walkpath.path_pos];
+ dx = dirx[pd->dir];
+ dy = diry[pd->dir];
+
+ ctype = map_getcell(pd->bl.m,x+dx,y+dy);
+ if(ctype == 1 || ctype == 5) {
+ pet_walktoxy_sub(pd);
+ return 0;
+ }
+
+ moveblock = ( x/BLOCK_SIZE != (x+dx)/BLOCK_SIZE || y/BLOCK_SIZE != (y+dy)/BLOCK_SIZE);
+
+ pd->state.state=MS_WALK;
+ map_foreachinmovearea(clif_petoutsight,pd->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,BL_PC,pd);
+
+ x += dx;
+ y += dy;
+
+ if(moveblock) map_delblock(&pd->bl);
+ pd->bl.x = x;
+ pd->bl.y = y;
+ if(moveblock) map_addblock(&pd->bl);
+
+ map_foreachinmovearea(clif_petinsight,pd->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,-dx,-dy,BL_PC,pd);
+ pd->state.state=MS_IDLE;
+ }
+ if((i=calc_next_walk_step(pd))>0){
+ i = i>>1;
+ if(i < 1 && pd->walkpath.path_half == 0)
+ i = 1;
+ pd->timer=add_timer(tick+i,pet_timer,pd->bl.id,pd->walkpath.path_pos);
+ pd->state.state=MS_WALK;
+
+ if(pd->walkpath.path_pos >= pd->walkpath.path_len)
+ clif_fixpetpos(pd);
+ }
+ return 0;
+}
+
+int pet_stopattack(struct pet_data *pd)
+{
+ nullpo_retr(0, pd);
+
+ pd->target_id=0;
+ if(pd->state.state == MS_ATTACK)
+ pet_changestate(pd,MS_IDLE,0);
+
+ return 0;
+}
+
+int pet_target_check(struct map_session_data *sd,struct block_list *bl,int type)
+{
+ struct pet_data *pd;
+ struct mob_data *md;
+ int rate,mode,race;
+
+ nullpo_retr(0, sd);
+
+ pd = sd->pd;
+
+ if(bl && pd && bl->type == BL_MOB && sd->pet.intimate > 900 && sd->pet.hungry > 0 && pd->class != battle_get_class(bl)
+ && pd->state.state != MS_DELAY) {
+ mode=mob_db[pd->class].mode;
+ race=mob_db[pd->class].race;
+ md=(struct mob_data *)bl;
+ if(md->bl.type != BL_MOB || pd->bl.m != md->bl.m || md->bl.prev == NULL ||
+ distance(pd->bl.x,pd->bl.y,md->bl.x,md->bl.y) > 13)
+ return 0;
+ if(mob_db[pd->class].mexp <= 0 && !(mode&0x20) && (md->option & 0x06 && race!=4 && race!=6) )
+ return 0;
+ if(!type) {
+ rate = sd->petDB->attack_rate;
+ rate = rate * (150 - (sd->pet.intimate - 1000))/100;
+ if(battle_config.pet_support_rate != 100)
+ rate = rate*battle_config.pet_support_rate/100;
+ if(sd->petDB->attack_rate > 0 && rate <= 0)
+ rate = 1;
+ }
+ else {
+ rate = sd->petDB->defence_attack_rate;
+ rate = rate * (150 - (sd->pet.intimate - 1000))/100;
+ if(battle_config.pet_support_rate != 100)
+ rate = rate*battle_config.pet_support_rate/100;
+ if(sd->petDB->defence_attack_rate > 0 && rate <= 0)
+ rate = 1;
+ }
+ if(rand()%10000 < rate) {
+ if(pd->target_id == 0 || rand()%10000 < sd->petDB->change_target_rate)
+ pd->target_id = bl->id;
+ }
+ }
+ return 0;
+}
+
+int pet_changestate(struct pet_data *pd,int state,int type)
+{
+ unsigned int tick;
+ int i;
+
+ nullpo_retr(0, pd);
+
+ if(pd->timer != -1)
+ delete_timer(pd->timer,pet_timer);
+ pd->timer=-1;
+ pd->state.state=state;
+
+ switch(state) {
+ case MS_WALK:
+ if((i=calc_next_walk_step(pd)) > 0){
+ i = i>>2;
+ pd->timer=add_timer(gettick()+i,pet_timer,pd->bl.id,0);
+ } else
+ pd->state.state=MS_IDLE;
+ break;
+ case MS_ATTACK:
+ tick = gettick();
+ i=DIFF_TICK(pd->attackabletime,tick);
+ if(i>0 && i<2000)
+ pd->timer=add_timer(pd->attackabletime,pet_timer,pd->bl.id,0);
+ else
+ pd->timer=add_timer(tick+1,pet_timer,pd->bl.id,0);
+ break;
+ case MS_DELAY:
+ pd->timer=add_timer(gettick()+type,pet_timer,pd->bl.id,0);
+ break;
+ }
+
+ return 0;
+}
+
+static int pet_timer(int tid,unsigned int tick,int id,int data)
+{
+ struct pet_data *pd;
+
+ pd=(struct pet_data*)map_id2bl(id);
+ if(pd == NULL || pd->bl.type != BL_PET)
+ return 1;
+
+ if(pd->timer != tid){
+ if(battle_config.error_log)
+ printf("pet_timer %d != %d\n",pd->timer,tid);
+ return 0;
+ }
+ pd->timer=-1;
+
+ if(pd->bl.prev == NULL)
+ return 1;
+
+ switch(pd->state.state){
+ case MS_WALK:
+ pet_walk(pd,tick,data);
+ break;
+ case MS_ATTACK:
+ pet_attack(pd,tick,data);
+ break;
+ case MS_DELAY:
+ pet_changestate(pd,MS_IDLE,0);
+ break;
+ default:
+ if(battle_config.error_log)
+ printf("pet_timer : %d ?\n",pd->state.state);
+ break;
+ }
+
+ return 0;
+}
+
+static int pet_walktoxy_sub(struct pet_data *pd)
+{
+ struct walkpath_data wpd;
+
+ nullpo_retr(0, pd);
+
+ if(path_search(&wpd,pd->bl.m,pd->bl.x,pd->bl.y,pd->to_x,pd->to_y,0))
+ return 1;
+ memcpy(&pd->walkpath,&wpd,sizeof(wpd));
+
+ pd->state.change_walk_target=0;
+ pet_changestate(pd,MS_WALK,0);
+ clif_movepet(pd);
+// if(battle_config.etc_log)
+// printf("walkstart\n");
+
+ return 0;
+}
+
+int pet_walktoxy(struct pet_data *pd,int x,int y)
+{
+ struct walkpath_data wpd;
+
+ nullpo_retr(0, pd);
+
+ if(pd->state.state == MS_WALK && path_search(&wpd,pd->bl.m,pd->bl.x,pd->bl.y,x,y,0))
+ return 1;
+
+ pd->to_x=x;
+ pd->to_y=y;
+
+ if(pd->state.state == MS_WALK) {
+ pd->state.change_walk_target=1;
+ } else {
+ return pet_walktoxy_sub(pd);
+ }
+
+ return 0;
+}
+
+int pet_stop_walking(struct pet_data *pd,int type)
+{
+ nullpo_retr(0, pd);
+
+ if(pd->state.state == MS_WALK || pd->state.state == MS_IDLE) {
+ pd->walkpath.path_len=0;
+ pd->to_x=pd->bl.x;
+ pd->to_y=pd->bl.y;
+ }
+ if(type&0x01)
+ clif_fixpetpos(pd);
+ if(type&~0xff)
+ pet_changestate(pd,MS_DELAY,type>>8);
+ else
+ pet_changestate(pd,MS_IDLE,0);
+
+ return 0;
+}
+
+static int pet_hungry(int tid,unsigned int tick,int id,int data)
+{
+ struct map_session_data *sd;
+ int interval,t;
+
+ sd=map_id2sd(id);
+ if(sd==NULL)
+ return 1;
+
+ if(sd->pet_hungry_timer != tid){
+ if(battle_config.error_log)
+ printf("pet_hungry_timer %d != %d\n",sd->pet_hungry_timer,tid);
+ return 0;
+ }
+ sd->pet_hungry_timer = -1;
+ if(!sd->status.pet_id || !sd->pd || !sd->petDB)
+ return 1;
+
+ sd->pet.hungry--;
+ t = sd->pet.intimate;
+ if(sd->pet.hungry < 0) {
+ if(sd->pd->target_id > 0)
+ pet_stopattack(sd->pd);
+ sd->pet.hungry = 0;
+ sd->pet.intimate -= battle_config.pet_hungry_friendly_decrease;
+ if(sd->pet.intimate <= 0) {
+ sd->pet.intimate = 0;
+ if(battle_config.pet_status_support && t > 0) {
+ if(sd->bl.prev != NULL)
+ pc_calcstatus(sd,0);
+ else
+ pc_calcstatus(sd,2);
+ }
+ }
+ clif_send_petdata(sd,1,sd->pet.intimate);
+ }
+ clif_send_petdata(sd,2,sd->pet.hungry);
+
+ if(battle_config.pet_hungry_delay_rate != 100)
+ interval = (sd->petDB->hungry_delay*battle_config.pet_hungry_delay_rate)/100;
+ else
+ interval = sd->petDB->hungry_delay;
+ if(interval <= 0)
+ interval = 1;
+ sd->pet_hungry_timer = add_timer(tick+interval,pet_hungry,sd->bl.id,0);
+
+ return 0;
+}
+
+int search_petDB_index(int key,int type)
+{
+ int i;
+
+ for(i=0;i<MAX_PET_DB;i++) {
+ if(pet_db[i].class <= 0)
+ continue;
+ switch(type) {
+ case PET_CLASS:
+ if(pet_db[i].class == key)
+ return i;
+ break;
+ case PET_CATCH:
+ if(pet_db[i].itemID == key)
+ return i;
+ break;
+ case PET_EGG:
+ if(pet_db[i].EggID == key)
+ return i;
+ break;
+ case PET_EQUIP:
+ if(pet_db[i].AcceID == key)
+ return i;
+ break;
+ case PET_FOOD:
+ if(pet_db[i].FoodID == key)
+ return i;
+ break;
+ default:
+ return -1;
+ }
+ }
+ return -1;
+}
+
+int pet_hungry_timer_delete(struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+
+ if(sd->pet_hungry_timer != -1) {
+ delete_timer(sd->pet_hungry_timer,pet_hungry);
+ sd->pet_hungry_timer = -1;
+ }
+
+ return 0;
+}
+
+int pet_remove_map(struct map_session_data *sd)
+{
+ nullpo_retr(0, sd);
+
+ if(sd->status.pet_id && sd->pd) {
+
+ struct pet_data *pd=sd->pd; // [Valaris]
+ if(pd->skillbonustimer!=-1) pd->skillbonustimer=-1;
+ if(pd->skillbonusduration!=-1) pd->skillbonusduration=-1;
+ if(pd->skilltype !=-1) pd->skilltype=-1;
+ if(pd->skillval !=-1) pd->skillval=-1;
+ if(pd->skilltimer!=-1) pd->skilltimer=-1;
+ if(pd->skillduration!=-1) pd->skillduration=-1;
+ if(pd->skillbonustype!=-1) pd->skillbonustype=-1;
+ if(pd->skillbonusval!=-1) pd->skillbonusval=-1;
+ if(sd->perfect_hiding==1) sd->perfect_hiding=0; // end additions
+
+ pet_changestate(sd->pd,MS_IDLE,0);
+ if(sd->pet_hungry_timer != -1)
+ pet_hungry_timer_delete(sd);
+ clif_clearchar_area(&sd->pd->bl,0);
+ map_delblock(&sd->pd->bl);
+ map_deliddb(&sd->pd->bl);
+ map_freeblock(sd->pd);
+ }
+ return 0;
+}
+struct delay_item_drop {
+ int m,x,y;
+ int nameid,amount;
+ struct map_session_data *first_sd,*second_sd,*third_sd;
+};
+
+struct delay_item_drop2 {
+ int m,x,y;
+ struct item item_data;
+ struct map_session_data *first_sd,*second_sd,*third_sd;
+};
+
+int pet_performance(struct map_session_data *sd)
+{
+ struct pet_data *pd;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, pd=sd->pd);
+
+ pet_stop_walking(pd,2000<<8);
+ clif_pet_performance(&pd->bl,rand()%pet_performance_val(sd) + 1);
+ // ルートしたItemを落とさせる
+ pet_lootitem_drop(pd,NULL);
+
+ return 0;
+}
+
+int pet_return_egg(struct map_session_data *sd)
+{
+ struct item tmp_item;
+ int flag;
+
+ nullpo_retr(0, sd);
+
+ if(sd->status.pet_id && sd->pd) {
+ struct pet_data *pd=sd->pd;
+ pet_remove_map(sd);
+ sd->status.pet_id = 0;
+ sd->pd = NULL;
+
+ if(sd->petDB == NULL)
+ return 1;
+ sd->pet.incuvate = 1;
+ memset(&tmp_item,0,sizeof(tmp_item));
+ tmp_item.nameid = sd->petDB->EggID;
+ tmp_item.identify = 1;
+ tmp_item.card[0] = 0xff00;
+ *((long *)(&tmp_item.card[1])) = sd->pet.pet_id;
+ tmp_item.card[3] = sd->pet.rename_flag;
+ if((flag = pc_additem(sd,&tmp_item,1))) {
+ clif_additem(sd,0,0,flag);
+ map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
+ }
+ if(battle_config.pet_status_support && sd->pet.intimate > 0) {
+ if(sd->bl.prev != NULL)
+ pc_calcstatus(sd,0);
+ else
+ pc_calcstatus(sd,2);
+ }
+ // ルートしたItemを落とさせる
+ pet_lootitem_drop(pd,sd);
+
+ intif_save_petdata(sd->status.account_id,&sd->pet);
+ pc_makesavestatus(sd);
+ chrif_save(sd);
+ storage_storage_save(sd);
+
+ sd->petDB = NULL;
+ }
+
+ return 0;
+}
+
+int pet_data_init(struct map_session_data *sd)
+{
+ struct pet_data *pd;
+ int i=0,interval=0;
+
+ nullpo_retr(1, sd);
+
+ if(sd->status.account_id != sd->pet.account_id || sd->status.char_id != sd->pet.char_id ||
+ sd->status.pet_id != sd->pet.pet_id) {
+ sd->status.pet_id = 0;
+ return 1;
+ }
+
+ i = search_petDB_index(sd->pet.class,PET_CLASS);
+ if(i < 0) {
+ sd->status.pet_id = 0;
+ return 1;
+ }
+ sd->petDB = &pet_db[i];
+ sd->pd = pd = (struct pet_data *)aCalloc(1,sizeof(struct pet_data));
+
+ pd->bl.m = sd->bl.m;
+ pd->bl.prev = pd->bl.next = NULL;
+ pd->bl.x = pd->to_x = sd->bl.x;
+ pd->bl.y = pd->to_y = sd->bl.y;
+ pet_calc_pos(pd,sd->bl.x,sd->bl.y,sd->dir);
+ pd->bl.x = pd->to_x;
+ pd->bl.y = pd->to_y;
+ pd->bl.id = npc_get_new_npc_id();
+ memcpy(pd->name,sd->pet.name,24);
+ pd->class = sd->pet.class;
+ pd->equip = sd->pet.equip;
+ pd->dir = sd->dir;
+ pd->speed = sd->petDB->speed;
+ pd->bl.subtype = MONS;
+ pd->bl.type = BL_PET;
+ memset(&pd->state,0,sizeof(pd->state));
+ pd->state.state = MS_IDLE;
+ pd->state.change_walk_target = 0;
+ pd->timer = -1;
+ pd->target_id = 0;
+ pd->move_fail_count = 0;
+ pd->next_walktime = pd->attackabletime = pd->last_thinktime = gettick();
+ pd->msd = sd;
+
+ map_addiddb(&pd->bl);
+
+ if(sd->pet_hungry_timer != -1)
+ pet_hungry_timer_delete(sd);
+ if(battle_config.pet_hungry_delay_rate != 100)
+ interval = (sd->petDB->hungry_delay*battle_config.pet_hungry_delay_rate)/100;
+ else
+ interval = sd->petDB->hungry_delay;
+ if(interval <= 0)
+ interval = 1;
+ sd->pet_hungry_timer = add_timer(gettick()+interval,pet_hungry,sd->bl.id,0);
+ pd->lootitem=(struct item *)aCalloc(PETLOOT_SIZE,sizeof(struct item));
+ pd->lootitem_count = 0;
+ pd->lootitem_weight = 0;
+ pd->lootitem_timer = gettick();
+ return 0;
+}
+
+int pet_birth_process(struct map_session_data *sd)
+{
+ nullpo_retr(1, sd);
+
+ if(sd->status.pet_id && sd->pet.incuvate == 1) {
+ sd->status.pet_id = 0;
+ return 1;
+ }
+
+ sd->pet.incuvate = 0;
+ sd->pet.account_id = sd->status.account_id;
+ sd->pet.char_id = sd->status.char_id;
+ sd->status.pet_id = sd->pet.pet_id;
+ if(pet_data_init(sd)) {
+ sd->status.pet_id = 0;
+ sd->pet.incuvate = 1;
+ sd->pet.account_id = 0;
+ sd->pet.char_id = 0;
+ return 1;
+ }
+
+ intif_save_petdata(sd->status.account_id,&sd->pet);
+ pc_makesavestatus(sd);
+ chrif_save(sd);
+ storage_storage_save(sd);
+ map_addblock(&sd->pd->bl);
+ clif_spawnpet(sd->pd);
+ clif_send_petdata(sd,0,0);
+ clif_send_petdata(sd,5,0x14);
+ clif_pet_equip(sd->pd,sd->pet.equip);
+ clif_send_petstatus(sd);
+
+ return 0;
+}
+
+int pet_recv_petdata(int account_id,struct s_pet *p,int flag)
+{
+ struct map_session_data *sd;
+
+ sd = map_id2sd(account_id);
+ if(sd == NULL)
+ return 1;
+ if(flag == 1) {
+ sd->status.pet_id = 0;
+ return 1;
+ }
+ memcpy(&sd->pet,p,sizeof(struct s_pet));
+ if(sd->pet.incuvate == 1)
+ pet_birth_process(sd);
+ else {
+ pet_data_init(sd);
+ if(sd->bl.prev != NULL) {
+ map_addblock(&sd->pd->bl);
+ clif_spawnpet(sd->pd);
+ clif_send_petdata(sd,0,0);
+ clif_send_petdata(sd,5,0x14);
+// clif_pet_equip(sd->pd,sd->pet.equip);
+ clif_send_petstatus(sd);
+ }
+ }
+ if(battle_config.pet_status_support && sd->pet.intimate > 0) {
+ if(sd->bl.prev != NULL)
+ pc_calcstatus(sd,0);
+ else
+ pc_calcstatus(sd,2);
+ }
+
+ return 0;
+}
+
+int pet_select_egg(struct map_session_data *sd,short egg_index)
+{
+ nullpo_retr(0, sd);
+
+ if(sd->status.inventory[egg_index].card[0] == (short)0xff00)
+ intif_request_petdata(sd->status.account_id,sd->status.char_id,*((long *)&sd->status.inventory[egg_index].card[1]));
+ else {
+ if(battle_config.error_log)
+ printf("wrong egg item inventory %d\n",egg_index);
+ }
+ pc_delitem(sd,egg_index,1,0);
+
+ return 0;
+}
+
+int pet_catch_process1(struct map_session_data *sd,int target_class)
+{
+ nullpo_retr(0, sd);
+
+ sd->catch_target_class = target_class;
+ clif_catch_process(sd);
+
+ return 0;
+}
+
+int pet_catch_process2(struct map_session_data *sd,int target_id)
+{
+ struct mob_data *md;
+ int i=0,pet_catch_rate=0;
+
+ nullpo_retr(1, sd);
+
+ md=(struct mob_data*)map_id2bl(target_id);
+ if(!md){
+ clif_pet_rulet(sd,0);
+ return 1;
+ }
+
+ i = search_petDB_index(md->class,PET_CLASS);
+ if(md == NULL || md->bl.type != BL_MOB || md->bl.prev == NULL || i < 0 || sd->catch_target_class != md->class) {
+ clif_pet_rulet(sd,0);
+ return 1;
+ }
+
+ //target_idによる敵→卵判定
+// if(battle_config.etc_log)
+// printf("mob_id = %d, mob_class = %d\n",md->bl.id,md->class);
+ //成功の場合
+ pet_catch_rate = (pet_db[i].capture + (sd->status.base_level - mob_db[md->class].lv)*30 + sd->paramc[5]*20)*(200 - md->hp*100/mob_db[md->class].max_hp)/100;
+ if(pet_catch_rate < 1) pet_catch_rate = 1;
+ if(battle_config.pet_catch_rate != 100)
+ pet_catch_rate = (pet_catch_rate*battle_config.pet_catch_rate)/100;
+
+ if(rand()%10000 < pet_catch_rate) {
+ mob_catch_delete(md,0);
+ clif_pet_rulet(sd,1);
+// if(battle_config.etc_log)
+// printf("rulet success %d\n",target_id);
+ intif_create_pet(sd->status.account_id,sd->status.char_id,pet_db[i].class,mob_db[pet_db[i].class].lv,
+ pet_db[i].EggID,0,pet_db[i].intimate,100,0,1,pet_db[i].jname);
+ }
+ else
+ clif_pet_rulet(sd,0);
+
+ return 0;
+}
+
+int pet_get_egg(int account_id,int pet_id,int flag)
+{
+ struct map_session_data *sd;
+ struct item tmp_item;
+ int i=0,ret=0;
+
+ if(!flag) {
+ sd = map_id2sd(account_id);
+ if(sd == NULL)
+ return 1;
+
+ i = search_petDB_index(sd->catch_target_class,PET_CLASS);
+ if(i >= 0) {
+ memset(&tmp_item,0,sizeof(tmp_item));
+ tmp_item.nameid = pet_db[i].EggID;
+ tmp_item.identify = 1;
+ tmp_item.card[0] = 0xff00;
+ *((long *)(&tmp_item.card[1])) = pet_id;
+ tmp_item.card[3] = sd->pet.rename_flag;
+ if((ret = pc_additem(sd,&tmp_item,1))) {
+ clif_additem(sd,0,0,ret);
+ map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
+ }
+ }
+ else
+ intif_delete_petdata(pet_id);
+ }
+
+ return 0;
+}
+
+int pet_menu(struct map_session_data *sd,int menunum)
+{
+ nullpo_retr(0, sd);
+
+ switch(menunum) {
+ case 0:
+ clif_send_petstatus(sd);
+ break;
+ case 1:
+ pet_food(sd);
+ break;
+ case 2:
+ pet_performance(sd);
+ break;
+ case 3:
+ pet_return_egg(sd);
+ break;
+ case 4:
+ pet_unequipitem(sd);
+ break;
+ }
+ return 0;
+}
+
+int pet_change_name(struct map_session_data *sd,char *name)
+{
+ int i;
+
+ nullpo_retr(1, sd);
+
+ if(sd->pet.rename_flag == 1 && battle_config.pet_rename == 0)
+ return 1;
+
+ for(i=0;i<24 && name[i];i++){
+ if( !(name[i]&0xe0) || name[i]==0x7f)
+ return 1;
+ }
+
+ pet_stop_walking(sd->pd,1);
+ memcpy(sd->pet.name,name,24);
+ memcpy(sd->pd->name,name,24);
+ clif_clearchar_area(&sd->pd->bl,0);
+ clif_spawnpet(sd->pd);
+ clif_send_petdata(sd,0,0);
+ clif_send_petdata(sd,5,0x14);
+ sd->pet.rename_flag = 1;
+ clif_pet_equip(sd->pd,sd->pet.equip);
+ clif_send_petstatus(sd);
+
+ return 0;
+}
+
+int pet_equipitem(struct map_session_data *sd,int index)
+{
+ int nameid;
+
+ nullpo_retr(1, sd);
+
+ nameid = sd->status.inventory[index].nameid;
+ if(sd->petDB == NULL)
+ return 1;
+ if(sd->petDB->AcceID == 0 || nameid != sd->petDB->AcceID || sd->pet.equip != 0) {
+ clif_equipitemack(sd,0,0,0);
+ return 1;
+ }
+ else {
+ pc_delitem(sd,index,1,0);
+ sd->pet.equip = sd->pd->equip = nameid;
+ pc_calcstatus(sd,0);
+ clif_pet_equip(sd->pd,nameid);
+ }
+
+ return 0;
+}
+
+int pet_unequipitem(struct map_session_data *sd)
+{
+ struct item tmp_item;
+ int nameid,flag;
+
+ nullpo_retr(1, sd);
+
+ if(sd->petDB == NULL)
+ return 1;
+ if(sd->pet.equip == 0)
+ return 1;
+
+ nameid = sd->pet.equip;
+ sd->pet.equip = sd->pd->equip = 0;
+ pc_calcstatus(sd,0);
+ clif_pet_equip(sd->pd,0);
+ memset(&tmp_item,0,sizeof(tmp_item));
+ tmp_item.nameid = nameid;
+ tmp_item.identify = 1;
+ if((flag = pc_additem(sd,&tmp_item,1))) {
+ clif_additem(sd,0,0,flag);
+ map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
+ }
+
+ return 0;
+}
+
+int pet_food(struct map_session_data *sd)
+{
+ int i,k,t;
+
+ nullpo_retr(1, sd);
+
+ if(sd->petDB == NULL)
+ return 1;
+ i=pc_search_inventory(sd,sd->petDB->FoodID);
+ if(i < 0) {
+ clif_pet_food(sd,sd->petDB->FoodID,0);
+ return 1;
+ }
+ pc_delitem(sd,i,1,0);
+ t = sd->pet.intimate;
+ if(sd->pet.hungry > 90)
+ sd->pet.intimate -= sd->petDB->r_full;
+ else if(sd->pet.hungry > 75) {
+ if(battle_config.pet_friendly_rate != 100)
+ k = (sd->petDB->r_hungry * battle_config.pet_friendly_rate)/100;
+ else
+ k = sd->petDB->r_hungry;
+ k = k >> 1;
+ if(k <= 0)
+ k = 1;
+ sd->pet.intimate += k;
+ }
+ else {
+ if(battle_config.pet_friendly_rate != 100)
+ k = (sd->petDB->r_hungry * battle_config.pet_friendly_rate)/100;
+ else
+ k = sd->petDB->r_hungry;
+ sd->pet.intimate += k;
+ }
+ if(sd->pet.intimate <= 0) {
+ sd->pet.intimate = 0;
+ if(battle_config.pet_status_support && t > 0) {
+ if(sd->bl.prev != NULL)
+ pc_calcstatus(sd,0);
+ else
+ pc_calcstatus(sd,2);
+ }
+ }
+ else if(sd->pet.intimate > 1000)
+ sd->pet.intimate = 1000;
+ sd->pet.hungry += sd->petDB->fullness;
+ if(sd->pet.hungry > 100)
+ sd->pet.hungry = 100;
+
+ clif_send_petdata(sd,2,sd->pet.hungry);
+ clif_send_petdata(sd,1,sd->pet.intimate);
+ clif_pet_food(sd,sd->petDB->FoodID,1);
+
+ return 0;
+}
+
+static int pet_randomwalk(struct pet_data *pd,int tick)
+{
+ const int retrycount=20;
+ int speed;
+
+ nullpo_retr(0, pd);
+
+ speed = battle_get_speed(&pd->bl);
+
+ if(DIFF_TICK(pd->next_walktime,tick) < 0){
+ int i,x,y,c,d=12-pd->move_fail_count;
+ if(d<5) d=5;
+ for(i=0;i<retrycount;i++){
+ int r=rand();
+ x=pd->bl.x+r%(d*2+1)-d;
+ y=pd->bl.y+r/(d*2+1)%(d*2+1)-d;
+ if((c=map_getcell(pd->bl.m,x,y))!=1 && c!=5 && pet_walktoxy(pd,x,y)==0){
+ pd->move_fail_count=0;
+ break;
+ }
+ if(i+1>=retrycount){
+ pd->move_fail_count++;
+ if(pd->move_fail_count>1000){
+ if(battle_config.error_log)
+ printf("PET cant move. hold position %d, class = %d\n",pd->bl.id,pd->class);
+ pd->move_fail_count=0;
+ pet_changestate(pd,MS_DELAY,60000);
+ return 0;
+ }
+ }
+ }
+ for(i=c=0;i<pd->walkpath.path_len;i++){
+ if(pd->walkpath.path[i]&1)
+ c+=speed*14/10;
+ else
+ c+=speed;
+ }
+ pd->next_walktime = tick+rand()%3000+3000+c;
+
+ return 1;
+ }
+ return 0;
+}
+
+static int pet_unlocktarget(struct pet_data *pd)
+{
+ nullpo_retr(0, pd);
+
+ pd->target_id=0;
+
+ return 0;
+}
+
+static int pet_ai_sub_hard(struct pet_data *pd,unsigned int tick)
+{
+ struct map_session_data *sd = pd->msd;
+ struct mob_data *md = NULL;
+ int dist,i=0,dx,dy,ret;
+ int mode,race;
+
+ nullpo_retr(0, pd);
+
+ sd = pd->msd;
+
+ if(pd->bl.prev == NULL || sd == NULL || sd->bl.prev == NULL)
+ return 0;
+
+ if(DIFF_TICK(tick,pd->last_thinktime) < MIN_PETTHINKTIME)
+ return 0;
+ pd->last_thinktime=tick;
+
+ if(pd->state.state == MS_DELAY || pd->bl.m != sd->bl.m)
+ return 0;
+ // ペットによるルート
+ if(!pd->target_id && pd->lootitem_count < PETLOOT_SIZE && pd->lootitem_count < pd->lootmax && pd->loot==1 && DIFF_TICK(gettick(),pd->lootitem_timer)>0)
+ map_foreachinarea(pet_ai_sub_hard_lootsearch,pd->bl.m,
+ pd->bl.x-AREA_SIZE*2,pd->bl.y-AREA_SIZE*2,
+ pd->bl.x+AREA_SIZE*2,pd->bl.y+AREA_SIZE*2,
+ BL_ITEM,pd,&i);
+
+ if(sd->pet.intimate > 0) {
+ dist = distance(sd->bl.x,sd->bl.y,pd->bl.x,pd->bl.y);
+ if(dist > 12) {
+ if(pd->target_id > 0)
+ pet_unlocktarget(pd);
+ if(pd->timer != -1 && pd->state.state == MS_WALK && distance(pd->to_x,pd->to_y,sd->bl.x,sd->bl.y) < 3)
+ return 0;
+ pd->speed = (sd->speed>>1);
+ if(pd->speed <= 0)
+ pd->speed = 1;
+ pet_calc_pos(pd,sd->bl.x,sd->bl.y,sd->dir);
+ if(pet_walktoxy(pd,pd->to_x,pd->to_y))
+ pet_randomwalk(pd,tick);
+ }
+ else if(pd->target_id - MAX_FLOORITEM > 0) {
+ mode=mob_db[pd->class].mode;
+ race=mob_db[pd->class].race;
+ md=(struct mob_data *)map_id2bl(pd->target_id);
+ if(md == NULL || md->bl.type != BL_MOB || pd->bl.m != md->bl.m || md->bl.prev == NULL ||
+ distance(pd->bl.x,pd->bl.y,md->bl.x,md->bl.y) > 13)
+ pet_unlocktarget(pd);
+ else if(mob_db[pd->class].mexp <= 0 && !(mode&0x20) && (md->option & 0x06 && race!=4 && race!=6) )
+ pet_unlocktarget(pd);
+ else if(!battle_check_range(&pd->bl,&md->bl,mob_db[pd->class].range)){
+ if(pd->timer != -1 && pd->state.state == MS_WALK && distance(pd->to_x,pd->to_y,md->bl.x,md->bl.y) < 2)
+ return 0;
+ if( !pet_can_reach(pd,md->bl.x,md->bl.y))
+ pet_unlocktarget(pd);
+ else {
+ i=0;
+ pd->speed = battle_get_speed(&pd->bl);
+ do {
+ if(i==0) { // 最初はAEGISと同じ方法で検索
+ dx=md->bl.x - pd->bl.x;
+ dy=md->bl.y - pd->bl.y;
+ if(dx<0) dx++;
+ else if(dx>0) dx--;
+ if(dy<0) dy++;
+ else if(dy>0) dy--;
+ }
+ else { // だめならAthena式(ランダム)
+ dx=md->bl.x - pd->bl.x + rand()%3 - 1;
+ dy=md->bl.y - pd->bl.y + rand()%3 - 1;
+ }
+ ret=pet_walktoxy(pd,pd->bl.x+dx,pd->bl.y+dy);
+ i++;
+ } while(ret && i<5);
+
+ if(ret) { // 移動不可能な所からの攻撃なら2歩下る
+ if(dx<0) dx=2;
+ else if(dx>0) dx=-2;
+ if(dy<0) dy=2;
+ else if(dy>0) dy=-2;
+ pet_walktoxy(pd,pd->bl.x+dx,pd->bl.y+dy);
+ }
+ }
+ }
+ else {
+ if(pd->state.state==MS_WALK)
+ pet_stop_walking(pd,1);
+ if(pd->state.state==MS_ATTACK)
+ return 0;
+ pet_changestate(pd,MS_ATTACK,0);
+ }
+ }
+ else if(pd->target_id > 0){ // ルート処理
+ struct block_list *bl_item;
+ struct flooritem_data *fitem;
+
+ bl_item = map_id2bl(pd->target_id);
+ if(bl_item == NULL || bl_item->type != BL_ITEM ||bl_item->m != pd->bl.m ||
+ (dist=distance(pd->bl.x,pd->bl.y,bl_item->x,bl_item->y))>=5){
+ // 遠すぎるかアイテムがなくなった
+ pet_unlocktarget(pd);
+ }
+ else if(dist){
+ if(pd->timer != -1 && pd->state.state!=MS_ATTACK && (DIFF_TICK(pd->next_walktime,tick)<0 || distance(pd->to_x,pd->to_y,bl_item->x,bl_item->y) <= 0))
+ return 0; // 既に移動中
+
+ pd->next_walktime=tick+500;
+ dx=bl_item->x - pd->bl.x;
+ dy=bl_item->y - pd->bl.y;
+
+ ret=pet_walktoxy(pd,pd->bl.x+dx,pd->bl.y+dy);
+ }
+ else{ // アイテムまでたどり着いた
+ fitem = (struct flooritem_data *)bl_item;
+ if(pd->state.state==MS_ATTACK)
+ return 0; // 攻撃中
+ if(pd->state.state==MS_WALK){ // 歩行中なら停止
+ pet_stop_walking(pd,1);
+ }
+ if(pd->lootitem_count < PETLOOT_SIZE && pd->lootitem_count < pd->lootmax){
+ memcpy(&pd->lootitem[pd->lootitem_count++],&fitem->item_data,sizeof(pd->lootitem[0]));
+ pd->lootitem_weight += itemdb_search(fitem->item_data.nameid)->weight*fitem->item_data.amount;
+ }
+ else if(pd->lootitem_count >= PETLOOT_SIZE || pd->lootitem_count >=pd->lootmax) {
+ pet_unlocktarget(pd);
+ return 0;
+ }
+ else {
+ if(pd->lootitem[0].card[0] == (short)0xff00)
+ intif_delete_petdata(*((long *)(&pd->lootitem[0].card[1])));
+ for(i=0;i<PETLOOT_SIZE-1;i++)
+ memcpy(&pd->lootitem[i],&pd->lootitem[i+1],sizeof(pd->lootitem[0]));
+ memcpy(&pd->lootitem[PETLOOT_SIZE-1],&fitem->item_data,sizeof(pd->lootitem[0]));
+ }
+ map_clearflooritem(bl_item->id);
+ pet_unlocktarget(pd);
+ }
+ }
+ else {
+ if(dist <= 3 || (pd->timer != -1 && pd->state.state == MS_WALK && distance(pd->to_x,pd->to_y,sd->bl.x,sd->bl.y) < 3) )
+ return 0;
+ pd->speed = battle_get_speed(&pd->bl);
+ pet_calc_pos(pd,sd->bl.x,sd->bl.y,sd->dir);
+ if(pet_walktoxy(pd,pd->to_x,pd->to_y))
+ pet_randomwalk(pd,tick);
+ }
+ }
+ else {
+ pd->speed = battle_get_speed(&pd->bl);
+ if(pd->state.state == MS_ATTACK)
+ pet_stopattack(pd);
+ pet_randomwalk(pd,tick);
+ }
+
+ return 0;
+}
+
+static int pet_ai_sub_foreachclient(struct map_session_data *sd,va_list ap)
+{
+ unsigned int tick;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, ap);
+
+ tick=va_arg(ap,unsigned int);
+ if(sd->status.pet_id && sd->pd && sd->petDB)
+ pet_ai_sub_hard(sd->pd,tick);
+
+ return 0;
+}
+
+static int pet_ai_hard(int tid,unsigned int tick,int id,int data)
+{
+ clif_foreachclient(pet_ai_sub_foreachclient,tick);
+
+ return 0;
+}
+
+int pet_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap)
+{
+ struct pet_data* pd;
+ int dist,*itc;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, pd=va_arg(ap,struct pet_data *));
+ nullpo_retr(0, itc=va_arg(ap,int *));
+
+ if(!pd->target_id){
+ struct flooritem_data *fitem = (struct flooritem_data *)bl;
+ struct map_session_data *sd = NULL;
+ // ルート権無し
+ if(fitem && fitem->first_get_id>0)
+ sd = map_id2sd(fitem->first_get_id);
+ // Removed [Valaris]
+ //if((pd->lootitem_weight + (itemdb_search(fitem->item_data.))->weight * fitem->item_data.amount) > battle_config.pet_weight)
+ // return 0;
+
+ if(!pd->lootitem || (pd->lootitem_count >= PETLOOT_SIZE) || (pd->lootitem_count >= pd->lootmax) || (sd && sd->pd != pd))
+ return 0;
+ if(bl->m == pd->bl.m && (dist=distance(pd->bl.x,pd->bl.y,bl->x,bl->y))<5){
+ if( pet_can_reach(pd,bl->x,bl->y) // 到達可能性判定
+ && rand()%1000<1000/(++(*itc)) ){ // 範囲内PCで等確率にする
+ pd->target_id=bl->id;
+ }
+ }
+ }
+ return 0;
+}
+int pet_lootitem_drop(struct pet_data *pd,struct map_session_data *sd)
+{
+ int i,flag=0;
+
+ if(pd){
+ if(pd->lootitem) {
+ for(i=0;i<pd->lootitem_count;i++) {
+ struct delay_item_drop2 *ditem;
+
+ ditem=(struct delay_item_drop2 *)aCalloc(1,sizeof(struct delay_item_drop2));
+ memcpy(&ditem->item_data,&pd->lootitem[i],sizeof(pd->lootitem[0]));
+ ditem->m = pd->bl.m;
+ ditem->x = pd->bl.x;
+ ditem->y = pd->bl.y;
+ ditem->first_sd = 0;
+ ditem->second_sd = 0;
+ ditem->third_sd = 0;
+ // 落とさないで直接PCのItem欄へ
+ if(sd){
+ if((flag = pc_additem(sd,&ditem->item_data,ditem->item_data.amount))){
+ clif_additem(sd,0,0,flag);
+ map_addflooritem(&ditem->item_data,ditem->item_data.amount,ditem->m,ditem->x,ditem->y,ditem->first_sd,ditem->second_sd,ditem->third_sd,0);
+ }
+ free(ditem);
+ }
+ else
+ add_timer(gettick()+540+i,pet_delay_item_drop2,(int)ditem,0);
+ }
+ pd->lootitem=NULL;
+ pd->lootitem=(struct item *)aCalloc(PETLOOT_SIZE,sizeof(struct item));
+ pd->lootitem_count = 0;
+ pd->lootitem_weight = 0;
+ pd->lootitem_timer = gettick()+10000; // 10*1000msの間拾わない
+ }
+ }
+ return 1;
+}
+
+int pet_delay_item_drop2(int tid,unsigned int tick,int id,int data)
+{
+ struct delay_item_drop2 *ditem;
+
+ ditem=(struct delay_item_drop2 *)id;
+
+ map_addflooritem(&ditem->item_data,ditem->item_data.amount,ditem->m,ditem->x,ditem->y,ditem->first_sd,ditem->second_sd,ditem->third_sd,0);
+
+ free(ditem);
+ return 0;
+}
+
+/*==========================================
+ * pet bonus giving skills [Valaris]
+ *------------------------------------------
+ */
+
+int pet_skill_bonus(struct map_session_data *sd,struct pet_data *pd,int type,int val,int duration,int timer,int data)
+{
+ if(pd==NULL || sd==NULL)
+ return 1;
+
+ pd->skillbonustype=type;
+ pd->skillbonusval=val;
+ pd->skillduration=duration;
+ pd->skilltimer=timer;
+
+ pd->skillbonustimer=add_timer(gettick()+pd->skilltimer*1000,pet_skill_bonus_timer,sd->bl.id,0);
+
+ return 0;
+
+}
+
+int pet_skill_bonus_timer(int tid,unsigned int tick,int id,int data)
+{
+ struct map_session_data *sd=(struct map_session_data*)map_id2bl(id);
+ struct pet_data *pd;
+
+ if(sd==NULL || sd->bl.type!=BL_PC)
+ return 1;
+
+ pd=sd->pd;
+
+ if(pd==NULL || pd->bl.type!=BL_PET)
+ return 1;
+
+ if(pd->skillbonustimer != tid)
+ return 0;
+
+ pd->skillbonustimer=-1;
+
+ pc_bonus(sd,pd->skillbonustype,pd->skillbonusval);
+ if(pd->skillbonustype < 56) clif_updatestatus(sd,pd->skillbonustype);
+ pd->skillbonusduration=add_timer(gettick()+pd->skillduration*1000,pet_skill_bonus_duration,sd->bl.id,0);
+
+ return 0;
+}
+
+int pet_skill_bonus_duration(int tid,unsigned int tick,int id,int data)
+{
+ struct map_session_data *sd=(struct map_session_data*)map_id2bl(id);
+ struct pet_data *pd;
+
+ if(sd==NULL || sd->bl.type!=BL_PC)
+ return 1;
+
+ pd=sd->pd;
+
+ if(pd==NULL || pd->bl.type!=BL_PET)
+ return 1;
+
+ if(pd->skillbonusduration != tid)
+ return 0;
+
+ pd->skillbonusduration=-1;
+
+ pc_bonus(sd,pd->skillbonustype,-pd->skillbonusval);
+ if(pd->skillbonustype < 56) clif_updatestatus(sd,pd->skillbonustype);
+
+ pet_skill_bonus(sd,pd,pd->skillbonustype,pd->skillbonusval,pd->skillduration,pd->skilltimer,0);
+
+ return 0;
+}
+
+int pet_recovery_timer(int tid,unsigned int tick,int id,int data)
+{
+ struct map_session_data *sd=(struct map_session_data*)map_id2bl(id);
+ struct pet_data *pd;
+
+ if(sd==NULL || sd->bl.type!=BL_PC)
+ return 1;
+
+ pd=sd->pd;
+
+ if(pd==NULL || pd->bl.type!=BL_PET)
+ return 1;
+
+ if(pd->skillbonustimer != tid)
+ return 0;
+
+ if(sd->sc_data[pd->skilltype].timer != -1)
+ skill_status_change_end(&sd->bl,pd->skilltype,-1);
+
+ pd->skillbonustimer=add_timer(gettick()+pd->skilltimer*1000,pet_recovery_timer,sd->bl.id,0);
+
+ return 0;
+}
+
+int pet_heal_timer(int tid,unsigned int tick,int id,int data)
+{
+ struct map_session_data *sd=(struct map_session_data*)map_id2bl(id);
+ struct pet_data *pd;
+
+ if(sd==NULL || sd->bl.type!=BL_PC)
+ return 1;
+
+ pd=sd->pd;
+
+ if(pd==NULL || pd->bl.type!=BL_PET)
+ return 1;
+
+ if(pd->skillbonustimer != tid)
+ return 0;
+
+ if(sd->status.hp < sd->status.max_hp * pd->skilltype/100) {
+ clif_skill_nodamage(&pd->bl,&sd->bl,AL_HEAL,pd->skillval,1);
+ pc_heal(sd,pd->skillval,0);
+ }
+
+ pd->skillbonustimer=add_timer(gettick()+pd->skilltimer*1000,pet_heal_timer,sd->bl.id,0);
+
+ return 0;
+}
+
+int pet_mag_timer(int tid,unsigned int tick,int id,int data)
+{
+ struct pet_data *pd;
+ struct map_session_data *sd=(struct map_session_data*)map_id2bl(id);
+
+ if(sd==NULL || sd->bl.type!=BL_PC)
+ return 1;
+
+ pd=sd->pd;
+
+ if(pd==NULL || pd->bl.type!=BL_PET)
+ return 1;
+
+ if(pd->skillbonustimer != tid)
+ return 0;
+
+ if(sd->status.hp < sd->status.max_hp * pd->skilltype/100 && sd->status.sp < sd->status.max_sp * pd->skillduration/100) {
+ clif_skill_nodamage(&pd->bl,&sd->bl,PR_MAGNIFICAT,pd->skillval,1);
+ skill_status_change_start(&sd->bl,SkillStatusChangeTable[PR_MAGNIFICAT],pd->skillval,0,0,0,skill_get_time(PR_MAGNIFICAT,pd->skillval),0 );
+ }
+
+ pd->skillbonustimer=add_timer(gettick()+pd->skilltimer*1000,pet_mag_timer,sd->bl.id,0);
+
+ return 0;
+}
+
+int pet_skillattack_timer(int tid,unsigned int tick,int id,int data)
+{
+ struct mob_data *md;
+ struct map_session_data *sd=(struct map_session_data*)map_id2bl(id);
+ struct pet_data *pd;
+
+ if(sd==NULL || sd->bl.type!=BL_PC)
+ return 1;
+
+ pd=sd->pd;
+
+ if(pd==NULL || pd->bl.type!=BL_PET)
+ return 1;
+
+ if(pd->skillbonustimer != tid)
+ return 0;
+
+ md=(struct mob_data *)map_id2bl(sd->attacktarget);
+ if(md == NULL || md->bl.type != BL_MOB || pd->bl.m != md->bl.m || md->bl.prev == NULL ||
+ distance(pd->bl.x,pd->bl.y,md->bl.x,md->bl.y) > 6) {
+ pd->target_id=0;
+ pd->skillbonustimer=add_timer(gettick()+100,pet_skillattack_timer,sd->bl.id,pd->skillduration);
+ return 0;
+ }
+
+ if(md && rand()%100 < sd->pet.intimate*pd->skilltimer/100 ) {
+ if(pd->skilltype==6 || pd->skilltype==176) {
+ skill_castend_nodamage_id(&pd->bl,&md->bl,pd->skilltype,pd->skillval,tick,0);
+ }
+
+ else if(pd->skilltype==110){
+ skill_castend_pos2(&pd->bl,md->bl.x,md->bl.y,pd->skilltype,pd->skillval,tick,0);
+ }
+
+ else if(pd->skilltype==91) {
+ skill_castend_pos2(&pd->bl,md->bl.x,md->bl.y,pd->skilltype,pd->skillval+rand()%100,tick,0);
+ }
+ else
+ skill_castend_damage_id(&pd->bl,&md->bl,pd->skilltype,pd->skillval,tick,0);
+ pd->skillbonustimer=add_timer(gettick()+1000,pet_skillattack_timer,sd->bl.id,0);
+ return 0;
+ }
+
+ pd->skillbonustimer=add_timer(gettick()+100,pet_skillattack_timer,sd->bl.id,0);
+
+ return 0;
+}
+
+/*==========================================
+ *ペットデータ読み込み
+ *------------------------------------------
+ */
+int read_petdb()
+{
+ FILE *fp;
+ char line[1024];
+ int i;
+ int j=0;
+ char *filename[]={"db/pet_db.txt","db/pet_db2.txt"};
+
+ memset(pet_db,0,sizeof(pet_db));
+ for(i=0;i<2;i++){
+ fp=fopen(filename[i],"r");
+ if(fp==NULL){
+ if(i>0)
+ continue;
+ printf("can't read %s\n",filename[i]);
+ return -1;
+ }
+ while(fgets(line,1020,fp)){
+ int nameid,i;
+ char *str[32],*p,*np;
+
+ if(line[0] == '/' && line[1] == '/')
+ continue;
+
+ for(i=0,p=line;i<20;i++){
+ if((np=strchr(p,','))!=NULL){
+ str[i]=p;
+ *np=0;
+ p=np+1;
+ } else {
+ str[i]=p;
+ p+=strlen(p);
+ }
+ }
+
+ nameid=atoi(str[0]);
+ if(nameid<=0 || nameid>2000)
+ continue;
+
+ //MobID,Name,JName,ItemID,EggID,AcceID,FoodID,"Fullness (1回の餌での満腹度増加率%)","HungryDeray (/min)","R_Hungry (空腹時餌やり親密度増加率%)","R_Full (とても満腹時餌やり親密度減少率%)","Intimate (捕獲時親密度%)","Die (死亡時親密度減少率%)","Capture (捕獲率%)",(Name)
+ pet_db[j].class = nameid;
+ memcpy(pet_db[j].name,str[1],24);
+ memcpy(pet_db[j].jname,str[2],24);
+ pet_db[j].itemID=atoi(str[3]);
+ pet_db[j].EggID=atoi(str[4]);
+ pet_db[j].AcceID=atoi(str[5]);
+ pet_db[j].FoodID=atoi(str[6]);
+ pet_db[j].fullness=atoi(str[7]);
+ pet_db[j].hungry_delay=atoi(str[8])*1000;
+ pet_db[j].r_hungry=atoi(str[9]);
+ if(pet_db[j].r_hungry <= 0)
+ pet_db[j].r_hungry=1;
+ pet_db[j].r_full=atoi(str[10]);
+ pet_db[j].intimate=atoi(str[11]);
+ pet_db[j].die=atoi(str[12]);
+ pet_db[j].capture=atoi(str[13]);
+ pet_db[j].speed=atoi(str[14]);
+ pet_db[j].s_perfor=(char)atoi(str[15]);
+ pet_db[j].talk_convert_class=atoi(str[16]);
+ pet_db[j].attack_rate=atoi(str[17]);
+ pet_db[j].defence_attack_rate=atoi(str[18]);
+ pet_db[j].change_target_rate=atoi(str[19]);
+ pet_db[j].script = NULL;
+ if((np=strchr(p,'{'))==NULL)
+ continue;
+ pet_db[j].script = parse_script(np,0);
+ j++;
+ }
+ fclose(fp);
+ printf("read %s done (count=%d)\n",filename[i],j);
+ }
+ return 0;
+}
+
+/*==========================================
+ * スキル関係初期化処理
+ *------------------------------------------
+ */
+int do_init_pet(void)
+{
+ read_petdb();
+
+ add_timer_func_list(pet_timer,"pet_timer");
+ add_timer_func_list(pet_hungry,"pet_hungry");
+ add_timer_func_list(pet_ai_hard,"pet_ai_hard");
+ add_timer_func_list(pet_skill_bonus_timer,"pet_skill_bonus_timer"); // [Valaris]
+ add_timer_func_list(pet_skill_bonus_duration,"pet_skill_bonus_duration"); // [Valaris]
+ add_timer_func_list(pet_recovery_timer,"pet_recovery_timer"); // [Valaris]
+ add_timer_func_list(pet_mag_timer,"pet_mag_timer"); // [Valaris]
+ add_timer_func_list(pet_heal_timer,"pet_heal_timer"); // [Valaris]
+ add_timer_func_list(pet_skillattack_timer,"pet_skillattack_timer"); // [Valaris]
+ add_timer_interval(gettick()+MIN_PETTHINKTIME,pet_ai_hard,0,0,MIN_PETTHINKTIME);
+
+ return 0;
+}
+
diff --git a/src/map/pet.h b/src/map/pet.h
new file mode 100644
index 000000000..b4ccf5ccb
--- /dev/null
+++ b/src/map/pet.h
@@ -0,0 +1,69 @@
+// $Id: pet.h,v 1.2 2004/09/25 05:32:18 MouseJstr Exp $
+#ifndef _PET_H_
+#define _PET_H_
+
+#define MAX_PET_DB 100
+#define PETLOOT_SIZE 20 // [Valaris]
+
+struct pet_db {
+ int class;
+ char name[24],jname[24];
+ int itemID;
+ int EggID;
+ int AcceID;
+ int FoodID;
+ int fullness;
+ int hungry_delay;
+ int r_hungry;
+ int r_full;
+ int intimate;
+ int die;
+ int capture;
+ int speed;
+ char s_perfor;
+ int talk_convert_class;
+ int attack_rate;
+ int defence_attack_rate;
+ int change_target_rate;
+ char *script;
+};
+extern struct pet_db pet_db[MAX_PET_DB];
+
+enum { PET_CLASS,PET_CATCH,PET_EGG,PET_EQUIP,PET_FOOD };
+
+int pet_hungry_val(struct map_session_data *sd);
+int pet_target_check(struct map_session_data *sd,struct block_list *bl,int type);
+int pet_stopattack(struct pet_data *pd);
+int pet_changestate(struct pet_data *pd,int state,int type);
+int pet_walktoxy(struct pet_data *pd,int x,int y);
+int pet_stop_walking(struct pet_data *pd,int type);
+int search_petDB_index(int key,int type);
+int pet_hungry_timer_delete(struct map_session_data *sd);
+int pet_remove_map(struct map_session_data *sd);
+int pet_data_init(struct map_session_data *sd);
+int pet_birth_process(struct map_session_data *sd);
+int pet_recv_petdata(int account_id,struct s_pet *p,int flag);
+int pet_select_egg(struct map_session_data *sd,short egg_index);
+int pet_catch_process1(struct map_session_data *sd,int target_class);
+int pet_catch_process2(struct map_session_data *sd,int target_id);
+int pet_get_egg(int account_id,int pet_id,int flag);
+int pet_menu(struct map_session_data *sd,int menunum);
+int pet_change_name(struct map_session_data *sd,char *name);
+int pet_equipitem(struct map_session_data *sd,int index);
+int pet_unequipitem(struct map_session_data *sd);
+int pet_food(struct map_session_data *sd);
+int pet_lootitem_drop(struct pet_data *pd,struct map_session_data *sd);
+int pet_delay_item_drop2(int tid,unsigned int tick,int id,int data);
+int pet_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap);
+int pet_skill_bonus(struct map_session_data *sd,struct pet_data *pd,int type,int val,int duration,int timer,int data);
+int pet_skill_bonus_timer(int tid,unsigned int tick,int id,int data); // [Valaris]
+int pet_skill_bonus_duration(int tid,unsigned int tick,int id,int data); // [Valaris]
+int pet_recovery_timer(int tid,unsigned int tick,int id,int data); // [Valaris]
+int pet_mag_timer(int tid,unsigned int tick,int id,int data); // [Valaris]
+int pet_heal_timer(int tid,unsigned int tick,int id,int data); // [Valaris]
+int pet_skillattack_timer(int tid,unsigned int tick,int id,int data); // [Valaris]
+
+int do_init_pet(void);
+
+#endif
+
diff --git a/src/map/script.c b/src/map/script.c
new file mode 100644
index 000000000..534e50cd1
--- /dev/null
+++ b/src/map/script.c
@@ -0,0 +1,6769 @@
+// $Id: script.c 148 2004-09-30 14:05:37Z MouseJstr $
+//#define DEBUG_FUNCIN
+//#define DEBUG_DISP
+//#define DEBUG_RUN
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef _WIN32
+#include <sys/time.h>
+#endif
+
+#include <time.h>
+
+#include "socket.h"
+#include "timer.h"
+#include "malloc.h"
+#include "lock.h"
+
+#include "map.h"
+#include "clif.h"
+#include "chrif.h"
+#include "itemdb.h"
+#include "pc.h"
+#include "script.h"
+#include "storage.h"
+#include "mob.h"
+#include "npc.h"
+#include "pet.h"
+#include "intif.h"
+#include "db.h"
+#include "skill.h"
+#include "chat.h"
+#include "battle.h"
+#include "party.h"
+#include "guild.h"
+#include "lock.h"
+#include "atcommand.h"
+#include "log.h"
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+#define SCRIPT_BLOCK_SIZE 256
+enum { LABEL_NEXTLINE=1,LABEL_START };
+static unsigned char * script_buf;
+static int script_pos,script_size;
+
+char *str_buf;
+int str_pos,str_size;
+static struct {
+ int type;
+ int str;
+ int backpatch;
+ int label;
+ int (*func)();
+ int val;
+ int next;
+} *str_data;
+int str_num=LABEL_START,str_data_size;
+int str_hash[16];
+
+static struct dbt *mapreg_db=NULL;
+static struct dbt *mapregstr_db=NULL;
+static int mapreg_dirty=-1;
+char mapreg_txt[256]="save/mapreg.txt";
+#define MAPREG_AUTOSAVE_INTERVAL (10*1000)
+
+static struct dbt *scriptlabel_db=NULL;
+static struct dbt *userfunc_db=NULL;
+
+struct dbt* script_get_label_db(){ return scriptlabel_db; }
+struct dbt* script_get_userfunc_db(){ if(!userfunc_db) userfunc_db=strdb_init(50); return userfunc_db; }
+
+int scriptlabel_final(void *k,void *d,va_list ap){ return 0; }
+static char pos[11][100] = {"頭","体","左手","右手","ローブ","靴","アクセサリー1","アクセサリー2","頭2","頭3","装着していない"};
+
+static struct Script_Config {
+ int warn_func_no_comma;
+ int warn_cmd_no_comma;
+ int warn_func_mismatch_paramnum;
+ int warn_cmd_mismatch_paramnum;
+ int check_cmdcount;
+ int check_gotocount;
+} script_config;
+static int parse_cmd_if=0;
+static int parse_cmd;
+
+/*==========================================
+ * ローカルプロトタイプ宣言 (必要な物のみ)
+ *------------------------------------------
+ */
+unsigned char* parse_subexpr(unsigned char *,int);
+int buildin_mes(struct script_state *st);
+int buildin_goto(struct script_state *st);
+int buildin_callsub(struct script_state *st);
+int buildin_callfunc(struct script_state *st);
+int buildin_return(struct script_state *st);
+int buildin_getarg(struct script_state *st);
+int buildin_next(struct script_state *st);
+int buildin_close(struct script_state *st);
+int buildin_close2(struct script_state *st);
+int buildin_menu(struct script_state *st);
+int buildin_rand(struct script_state *st);
+int buildin_warp(struct script_state *st);
+int buildin_areawarp(struct script_state *st);
+int buildin_heal(struct script_state *st);
+int buildin_itemheal(struct script_state *st);
+int buildin_percentheal(struct script_state *st);
+int buildin_jobchange(struct script_state *st);
+int buildin_input(struct script_state *st);
+int buildin_setlook(struct script_state *st);
+int buildin_set(struct script_state *st);
+int buildin_setarray(struct script_state *st);
+int buildin_cleararray(struct script_state *st);
+int buildin_copyarray(struct script_state *st);
+int buildin_getarraysize(struct script_state *st);
+int buildin_deletearray(struct script_state *st);
+int buildin_getelementofarray(struct script_state *st);
+int buildin_if(struct script_state *st);
+int buildin_getitem(struct script_state *st);
+int buildin_getitem2(struct script_state *st);
+int buildin_makeitem(struct script_state *st);
+int buildin_delitem(struct script_state *st);
+int buildin_viewpoint(struct script_state *st);
+int buildin_countitem(struct script_state *st);
+int buildin_checkweight(struct script_state *st);
+int buildin_readparam(struct script_state *st);
+int buildin_getcharid(struct script_state *st);
+int buildin_getpartyname(struct script_state *st);
+int buildin_getpartymember(struct script_state *st);
+int buildin_getguildname(struct script_state *st);
+int buildin_getguildmaster(struct script_state *st);
+int buildin_getguildmasterid(struct script_state *st);
+int buildin_strcharinfo(struct script_state *st);
+int buildin_getequipid(struct script_state *st);
+int buildin_getequipname(struct script_state *st);
+int buildin_getbrokenid(struct script_state *st); // [Valaris]
+int buildin_repair(struct script_state *st); // [Valaris]
+int buildin_getequipisequiped(struct script_state *st);
+int buildin_getequipisenableref(struct script_state *st);
+int buildin_getequipisidentify(struct script_state *st);
+int buildin_getequiprefinerycnt(struct script_state *st);
+int buildin_getequipweaponlv(struct script_state *st);
+int buildin_getequippercentrefinery(struct script_state *st);
+int buildin_successrefitem(struct script_state *st);
+int buildin_failedrefitem(struct script_state *st);
+int buildin_cutin(struct script_state *st);
+int buildin_cutincard(struct script_state *st);
+int buildin_statusup(struct script_state *st);
+int buildin_statusup2(struct script_state *st);
+int buildin_bonus(struct script_state *st);
+int buildin_bonus2(struct script_state *st);
+int buildin_bonus3(struct script_state *st);
+int buildin_skill(struct script_state *st);
+int buildin_guildskill(struct script_state *st);
+int buildin_getskilllv(struct script_state *st);
+int buildin_getgdskilllv(struct script_state *st);
+int buildin_basicskillcheck(struct script_state *st);
+int buildin_getgmlevel(struct script_state *st);
+int buildin_end(struct script_state *st);
+int buildin_checkoption(struct script_state *st);
+int buildin_setoption(struct script_state *st);
+int buildin_setcart(struct script_state *st);
+int buildin_checkcart(struct script_state *st); // check cart [Valaris]
+int buildin_setfalcon(struct script_state *st);
+int buildin_checkfalcon(struct script_state *st); // check falcon [Valaris]
+int buildin_setriding(struct script_state *st);
+int buildin_checkriding(struct script_state *st); // check for pecopeco [Valaris]
+int buildin_savepoint(struct script_state *st);
+int buildin_gettimetick(struct script_state *st);
+int buildin_gettime(struct script_state *st);
+int buildin_gettimestr(struct script_state *st);
+int buildin_openstorage(struct script_state *st);
+int buildin_guildopenstorage(struct script_state *st);
+int buildin_itemskill(struct script_state *st);
+int buildin_produce(struct script_state *st);
+int buildin_monster(struct script_state *st);
+int buildin_areamonster(struct script_state *st);
+int buildin_killmonster(struct script_state *st);
+int buildin_killmonsterall(struct script_state *st);
+int buildin_doevent(struct script_state *st);
+int buildin_donpcevent(struct script_state *st);
+int buildin_addtimer(struct script_state *st);
+int buildin_deltimer(struct script_state *st);
+int buildin_addtimercount(struct script_state *st);
+int buildin_initnpctimer(struct script_state *st);
+int buildin_stopnpctimer(struct script_state *st);
+int buildin_startnpctimer(struct script_state *st);
+int buildin_setnpctimer(struct script_state *st);
+int buildin_getnpctimer(struct script_state *st);
+int buildin_announce(struct script_state *st);
+int buildin_mapannounce(struct script_state *st);
+int buildin_areaannounce(struct script_state *st);
+int buildin_getusers(struct script_state *st);
+int buildin_getmapusers(struct script_state *st);
+int buildin_getareausers(struct script_state *st);
+int buildin_getareadropitem(struct script_state *st);
+int buildin_enablenpc(struct script_state *st);
+int buildin_disablenpc(struct script_state *st);
+int buildin_enablearena(struct script_state *st); // Added by RoVeRT
+int buildin_disablearena(struct script_state *st); // Added by RoVeRT
+int buildin_hideoffnpc(struct script_state *st);
+int buildin_hideonnpc(struct script_state *st);
+int buildin_sc_start(struct script_state *st);
+int buildin_sc_start2(struct script_state *st);
+int buildin_sc_end(struct script_state *st);
+int buildin_getscrate(struct script_state *st);
+int buildin_debugmes(struct script_state *st);
+int buildin_catchpet(struct script_state *st);
+int buildin_birthpet(struct script_state *st);
+int buildin_resetlvl(struct script_state *st);
+int buildin_resetstatus(struct script_state *st);
+int buildin_resetskill(struct script_state *st);
+int buildin_changebase(struct script_state *st);
+int buildin_changesex(struct script_state *st);
+int buildin_waitingroom(struct script_state *st);
+int buildin_delwaitingroom(struct script_state *st);
+int buildin_enablewaitingroomevent(struct script_state *st);
+int buildin_disablewaitingroomevent(struct script_state *st);
+int buildin_getwaitingroomstate(struct script_state *st);
+int buildin_warpwaitingpc(struct script_state *st);
+int buildin_attachrid(struct script_state *st);
+int buildin_detachrid(struct script_state *st);
+int buildin_isloggedin(struct script_state *st);
+int buildin_setmapflagnosave(struct script_state *st);
+int buildin_setmapflag(struct script_state *st);
+int buildin_removemapflag(struct script_state *st);
+int buildin_pvpon(struct script_state *st);
+int buildin_pvpoff(struct script_state *st);
+int buildin_gvgon(struct script_state *st);
+int buildin_gvgoff(struct script_state *st);
+int buildin_emotion(struct script_state *st);
+int buildin_maprespawnguildid(struct script_state *st);
+int buildin_agitstart(struct script_state *st); // <Agit>
+int buildin_agitend(struct script_state *st);
+int buildin_agitcheck(struct script_state *st); // <Agitcheck>
+int buildin_flagemblem(struct script_state *st); // Flag Emblem
+int buildin_getcastlename(struct script_state *st);
+int buildin_getcastledata(struct script_state *st);
+int buildin_setcastledata(struct script_state *st);
+int buildin_requestguildinfo(struct script_state *st);
+int buildin_getequipcardcnt(struct script_state *st);
+int buildin_successremovecards(struct script_state *st);
+int buildin_failedremovecards(struct script_state *st);
+int buildin_marriage(struct script_state *st);
+int buildin_wedding_effect(struct script_state *st);
+int buildin_divorce(struct script_state *st);
+int buildin_getitemname(struct script_state *st);
+int buildin_makepet(struct script_state *st);
+int buildin_getexp(struct script_state *st);
+int buildin_getinventorylist(struct script_state *st);
+int buildin_getskilllist(struct script_state *st);
+int buildin_clearitem(struct script_state *st);
+int buildin_classchange(struct script_state *st);
+int buildin_misceffect(struct script_state *st);
+int buildin_soundeffect(struct script_state *st);
+int buildin_setcastledata(struct script_state *st);
+int buildin_mapwarp(struct script_state *st);
+int buildin_inittimer(struct script_state *st);
+int buildin_stoptimer(struct script_state *st);
+int buildin_cmdothernpc(struct script_state *st);
+int buildin_mobcount(struct script_state *st);
+int buildin_strmobinfo(struct script_state *st); // Script for displaying mob info [Valaris]
+int buildin_guardian(struct script_state *st); // Script for displaying mob info [Valaris]
+int buildin_guardianinfo(struct script_state *st); // Script for displaying mob info [Valaris]
+int buildin_petskillbonus(struct script_state *st); // petskillbonus [Valaris]
+int buildin_petrecovery(struct script_state *st); // pet skill for curing status [Valaris]
+int buildin_petloot(struct script_state *st); // pet looting [Valaris]
+int buildin_petheal(struct script_state *st); // pet healing [Valaris]
+int buildin_petmag(struct script_state *st); // pet magnificat [Valaris]
+int buildin_petskillattack(struct script_state *st); // pet skill attacks [Valaris]
+int buildin_npcskilleffect(struct script_state *st); // skill effects for npcs [Valaris]
+int buildin_specialeffect(struct script_state *st); // special effect script [Valaris]
+int buildin_specialeffect2(struct script_state *st); // special effect script [Valaris]
+int buildin_nude(struct script_state *st); // nude [Valaris]
+int buildin_gmcommand(struct script_state *st); // [MouseJstr]
+int buildin_movenpc(struct script_state *st); // [MouseJstr]
+int buildin_message(struct script_state *st); // [MouseJstr]
+int buildin_npctalk(struct script_state *st); // [Valaris]
+int buildin_hasitems(struct script_state *st); // [Valaris]
+int buildin_getlook(struct script_state *st); //Lorky [Lupus]
+int buildin_getsavepoint(struct script_state *st); //Lorky [Lupus]
+int buildin_npcspeed(struct script_state *st); // [Valaris]
+int buildin_npcwalkto(struct script_state *st); // [Valaris]
+int buildin_npcstop(struct script_state *st); // [Valaris]
+
+
+void push_val(struct script_stack *stack,int type,int val);
+int run_func(struct script_state *st);
+
+int mapreg_setreg(int num,int val);
+int mapreg_setregstr(int num,const char *str);
+
+struct {
+ int (*func)();
+ char *name;
+ char *arg;
+} buildin_func[]={
+ {buildin_mes,"mes","s"},
+ {buildin_next,"next",""},
+ {buildin_close,"close",""},
+ {buildin_close2,"close2",""},
+ {buildin_menu,"menu","*"},
+ {buildin_goto,"goto","l"},
+ {buildin_callsub,"callsub","i*"},
+ {buildin_callfunc,"callfunc","s*"},
+ {buildin_return,"return","*"},
+ {buildin_getarg,"getarg","i"},
+ {buildin_jobchange,"jobchange","i*"},
+ {buildin_input,"input","*"},
+ {buildin_warp,"warp","sii"},
+ {buildin_areawarp,"areawarp","siiiisii"},
+ {buildin_setlook,"setlook","ii"},
+ {buildin_set,"set","ii"},
+ {buildin_setarray,"setarray","ii*"},
+ {buildin_cleararray,"cleararray","iii"},
+ {buildin_copyarray,"copyarray","iii"},
+ {buildin_getarraysize,"getarraysize","i"},
+ {buildin_deletearray,"deletearray","ii"},
+ {buildin_getelementofarray,"getelementofarray","ii"},
+ {buildin_if,"if","i*"},
+ {buildin_getitem,"getitem","ii**"},
+ {buildin_getitem2,"getitem2","iiiiiiiii*"},
+ {buildin_makeitem,"makeitem","iisii"},
+ {buildin_delitem,"delitem","ii"},
+ {buildin_cutin,"cutin","si"},
+ {buildin_cutincard,"cutincard","i"},
+ {buildin_viewpoint,"viewpoint","iiiii"},
+ {buildin_heal,"heal","ii"},
+ {buildin_itemheal,"itemheal","ii"},
+ {buildin_percentheal,"percentheal","ii"},
+ {buildin_rand,"rand","i*"},
+ {buildin_countitem,"countitem","i"},
+ {buildin_checkweight,"checkweight","ii"},
+ {buildin_readparam,"readparam","i*"},
+ {buildin_getcharid,"getcharid","i*"},
+ {buildin_getpartyname,"getpartyname","i"},
+ {buildin_getpartymember,"getpartymember","i"},
+ {buildin_getguildname,"getguildname","i"},
+ {buildin_getguildmaster,"getguildmaster","i"},
+ {buildin_getguildmasterid,"getguildmasterid","i"},
+ {buildin_strcharinfo,"strcharinfo","i"},
+ {buildin_getequipid,"getequipid","i"},
+ {buildin_getequipname,"getequipname","i"},
+ {buildin_getbrokenid,"getbrokenid","i"}, // [Valaris]
+ {buildin_repair,"repair","i"}, // [Valaris]
+ {buildin_getequipisequiped,"getequipisequiped","i"},
+ {buildin_getequipisenableref,"getequipisenableref","i"},
+ {buildin_getequipisidentify,"getequipisidentify","i"},
+ {buildin_getequiprefinerycnt,"getequiprefinerycnt","i"},
+ {buildin_getequipweaponlv,"getequipweaponlv","i"},
+ {buildin_getequippercentrefinery,"getequippercentrefinery","i"},
+ {buildin_successrefitem,"successrefitem","i"},
+ {buildin_failedrefitem,"failedrefitem","i"},
+ {buildin_statusup,"statusup","i"},
+ {buildin_statusup2,"statusup2","ii"},
+ {buildin_bonus,"bonus","ii"},
+ {buildin_bonus2,"bonus2","iii"},
+ {buildin_bonus3,"bonus3","iiii"},
+ {buildin_skill,"skill","ii*"},
+ {buildin_guildskill,"guildskill","ii"},
+ {buildin_getskilllv,"getskilllv","i"},
+ {buildin_getgdskilllv,"getgdskilllv","ii"},
+ {buildin_basicskillcheck,"basicskillcheck","*"},
+ {buildin_getgmlevel,"getgmlevel","*"},
+ {buildin_end,"end",""},
+ {buildin_end,"break",""},
+ {buildin_checkoption,"checkoption","i"},
+ {buildin_setoption,"setoption","i"},
+ {buildin_setcart,"setcart",""},
+ {buildin_checkcart,"checkcart","*"}, //fixed by Lupus (added '*')
+ {buildin_setfalcon,"setfalcon",""},
+ {buildin_checkfalcon,"checkfalcon","*"}, //fixed by Lupus (fixed wrong pointer, added '*')
+ {buildin_setriding,"setriding",""},
+ {buildin_checkriding,"checkriding","*"}, //fixed by Lupus (fixed wrong pointer, added '*')
+ {buildin_savepoint,"save","sii"},
+ {buildin_savepoint,"savepoint","sii"},
+ {buildin_gettimetick,"gettimetick","i"},
+ {buildin_gettime,"gettime","i"},
+ {buildin_gettimestr,"gettimestr","si"},
+ {buildin_openstorage,"openstorage",""},
+ {buildin_guildopenstorage,"guildopenstorage","*"},
+ {buildin_itemskill,"itemskill","iis"},
+ {buildin_produce,"produce","i"},
+ {buildin_monster,"monster","siisii*"},
+ {buildin_areamonster,"areamonster","siiiisii*"},
+ {buildin_killmonster,"killmonster","ss"},
+ {buildin_killmonsterall,"killmonsterall","s"},
+ {buildin_doevent,"doevent","s"},
+ {buildin_donpcevent,"donpcevent","s"},
+ {buildin_addtimer,"addtimer","is"},
+ {buildin_deltimer,"deltimer","s"},
+ {buildin_addtimercount,"addtimercount","si"},
+ {buildin_initnpctimer,"initnpctimer","*"},
+ {buildin_stopnpctimer,"stopnpctimer","*"},
+ {buildin_startnpctimer,"startnpctimer","*"},
+ {buildin_setnpctimer,"setnpctimer","*"},
+ {buildin_getnpctimer,"getnpctimer","i*"},
+ {buildin_announce,"announce","si"},
+ {buildin_mapannounce,"mapannounce","ssi"},
+ {buildin_areaannounce,"areaannounce","siiiisi"},
+ {buildin_getusers,"getusers","i"},
+ {buildin_getmapusers,"getmapusers","s"},
+ {buildin_getareausers,"getareausers","siiii"},
+ {buildin_getareadropitem,"getareadropitem","siiiii"},
+ {buildin_enablenpc,"enablenpc","s"},
+ {buildin_disablenpc,"disablenpc","s"},
+ {buildin_enablearena,"enablearena",""}, // Added by RoVeRT
+ {buildin_disablearena,"disablearena",""}, // Added by RoVeRT
+ {buildin_hideoffnpc,"hideoffnpc","s"},
+ {buildin_hideonnpc,"hideonnpc","s"},
+ {buildin_sc_start,"sc_start","iii*"},
+ {buildin_sc_start2,"sc_start2","iiii*"},
+ {buildin_sc_end,"sc_end","i"},
+ {buildin_getscrate,"getscrate","ii*"},
+ {buildin_debugmes,"debugmes","s"},
+ {buildin_catchpet,"pet","i"},
+ {buildin_birthpet,"bpet",""},
+ {buildin_resetlvl,"resetlvl","i"},
+ {buildin_resetstatus,"resetstatus",""},
+ {buildin_resetskill,"resetskill",""},
+ {buildin_changebase,"changebase","i"},
+ {buildin_changesex,"changesex",""},
+ {buildin_waitingroom,"waitingroom","si*"},
+ {buildin_warpwaitingpc,"warpwaitingpc","sii"},
+ {buildin_delwaitingroom,"delwaitingroom","*"},
+ {buildin_enablewaitingroomevent,"enablewaitingroomevent","*"},
+ {buildin_disablewaitingroomevent,"disablewaitingroomevent","*"},
+ {buildin_getwaitingroomstate,"getwaitingroomstate","i*"},
+ {buildin_warpwaitingpc,"warpwaitingpc","sii*"},
+ {buildin_attachrid,"attachrid","i"},
+ {buildin_detachrid,"detachrid",""},
+ {buildin_isloggedin,"isloggedin","i"},
+ {buildin_setmapflagnosave,"setmapflagnosave","ssii"},
+ {buildin_setmapflag,"setmapflag","si"},
+ {buildin_removemapflag,"removemapflag","si"},
+ {buildin_pvpon,"pvpon","s"},
+ {buildin_pvpoff,"pvpoff","s"},
+ {buildin_gvgon,"gvgon","s"},
+ {buildin_gvgoff,"gvgoff","s"},
+ {buildin_emotion,"emotion","i"},
+ {buildin_maprespawnguildid,"maprespawnguildid","sii"},
+ {buildin_agitstart,"agitstart",""}, // <Agit>
+ {buildin_agitend,"agitend",""},
+ {buildin_agitcheck,"agitcheck","i"}, // <Agitcheck>
+ {buildin_flagemblem,"flagemblem","i"}, // Flag Emblem
+ {buildin_getcastlename,"getcastlename","s"},
+ {buildin_getcastledata,"getcastledata","si*"},
+ {buildin_setcastledata,"setcastledata","sii"},
+ {buildin_requestguildinfo,"requestguildinfo","i*"},
+ {buildin_getequipcardcnt,"getequipcardcnt","i"},
+ {buildin_successremovecards,"successremovecards","i"},
+ {buildin_failedremovecards,"failedremovecards","ii"},
+ {buildin_marriage,"marriage","s"},
+ {buildin_wedding_effect,"wedding",""},
+ {buildin_divorce,"divorce",""},
+ {buildin_getitemname,"getitemname","i"},
+ {buildin_makepet,"makepet","i"},
+ {buildin_getexp,"getexp","ii"},
+ {buildin_getinventorylist,"getinventorylist",""},
+ {buildin_getskilllist,"getskilllist",""},
+ {buildin_clearitem,"clearitem",""},
+ {buildin_classchange,"classchange","ii"},
+ {buildin_misceffect,"misceffect","i"},
+ {buildin_soundeffect,"soundeffect","si"},
+ {buildin_strmobinfo,"strmobinfo","ii"}, // display mob data [Valaris]
+ {buildin_guardian,"guardian","siisii*i"}, // summon guardians
+ {buildin_guardianinfo,"guardianinfo","i"}, // display guardian data [Valaris]
+ {buildin_petskillbonus,"petskillbonus","iiii"}, // [Valaris]
+ {buildin_petrecovery,"petrecovery","ii"}, // [Valaris]
+ {buildin_petloot,"petloot","i"}, // [Valaris]
+ {buildin_petheal,"petheal","iii"}, // [Valaris]
+ {buildin_petmag,"petmag","iiii"}, // [Valaris]
+ {buildin_petskillattack,"petskillattack","iiii"}, // [Valaris]
+ {buildin_npcskilleffect,"npcskilleffect","iiii"}, // npc skill effect [Valaris]
+ {buildin_specialeffect,"specialeffect","i"}, // npc skill effect [Valaris]
+ {buildin_specialeffect2,"specialeffect2","i"}, // skill effect on players[Valaris]
+ {buildin_nude,"nude",""}, // nude command [Valaris]
+ {buildin_mapwarp,"mapwarp","ssii"}, // Added by RoVeRT
+ {buildin_inittimer,"inittimer",""},
+ {buildin_stoptimer,"stoptimer",""},
+ {buildin_cmdothernpc,"cmdothernpc","ss"},
+ {buildin_gmcommand,"gmcommand","*"}, // [MouseJstr]
+// {buildin_movenpc,"movenpc","siis"}, // [MouseJstr]
+ {buildin_message,"message","s*"}, // [MouseJstr]
+ {buildin_npctalk,"npctalk","*"}, // [Valaris]
+ {buildin_hasitems,"hasitems","*"}, // [Valaris]
+ {buildin_mobcount,"mobcount","ss"},
+ {buildin_getlook,"getlook","i"},
+ {buildin_getsavepoint,"getsavepoint","i"},
+ {buildin_npcspeed,"npcspeed","i"}, // [Valaris]
+ {buildin_npcwalkto,"npcwalkto","ii"}, // [Valaris]
+ {buildin_npcstop,"npcstop",""}, // [Valaris]
+ {NULL,NULL,NULL},
+};
+int buildin_message(struct script_state *st); // [MouseJstr]
+
+
+enum {
+ C_NOP,C_POS,C_INT,C_PARAM,C_FUNC,C_STR,C_CONSTSTR,C_ARG,
+ C_NAME,C_EOL, C_RETINFO,
+
+ C_LOR,C_LAND,C_LE,C_LT,C_GE,C_GT,C_EQ,C_NE, //operator
+ C_XOR,C_OR,C_AND,C_ADD,C_SUB,C_MUL,C_DIV,C_MOD,C_NEG,C_LNOT,C_NOT,C_R_SHIFT,C_L_SHIFT
+};
+
+/*==========================================
+ * 文字列のハッシュを計算
+ *------------------------------------------
+ */
+static int calc_hash(const unsigned char *p)
+{
+ int h=0;
+ while(*p){
+ h=(h<<1)+(h>>3)+(h>>5)+(h>>8);
+ h+=*p++;
+ }
+ return h&15;
+}
+
+/*==========================================
+ * str_dataの中に名前があるか検索する
+ *------------------------------------------
+ */
+// 既存のであれば番号、無ければ-1
+static int search_str(const unsigned char *p)
+{
+ int i;
+ i=str_hash[calc_hash(p)];
+ while(i){
+ if(strcmp(str_buf+str_data[i].str,p)==0){
+ return i;
+ }
+ i=str_data[i].next;
+ }
+ return -1;
+}
+
+/*==========================================
+ * str_dataに名前を登録
+ *------------------------------------------
+ */
+// 既存のであれば番号、無ければ登録して新規番号
+static int add_str(const unsigned char *p)
+{
+ int i;
+ char *lowcase;
+
+ lowcase=strdup(p);
+ for(i=0;lowcase[i];i++)
+ lowcase[i]=tolower(lowcase[i]);
+ if((i=search_str(lowcase))>=0){
+ free(lowcase);
+ return i;
+ }
+ free(lowcase);
+
+ i=calc_hash(p);
+ if(str_hash[i]==0){
+ str_hash[i]=str_num;
+ } else {
+ i=str_hash[i];
+ for(;;){
+ if(strcmp(str_buf+str_data[i].str,p)==0){
+ return i;
+ }
+ if(str_data[i].next==0)
+ break;
+ i=str_data[i].next;
+ }
+ str_data[i].next=str_num;
+ }
+ if(str_num>=str_data_size){
+ str_data_size+=128;
+ str_data=aRealloc(str_data,sizeof(str_data[0])*str_data_size);
+ memset(str_data + (str_data_size - 128), '\0', 128);
+ }
+ while(str_pos+strlen(p)+1>=str_size){
+ str_size+=256;
+ str_buf=(char *)aRealloc(str_buf,str_size);
+ memset(str_buf + (str_size - 256), '\0', 256);
+ }
+ strcpy(str_buf+str_pos,p);
+ str_data[str_num].type=C_NOP;
+ str_data[str_num].str=str_pos;
+ str_data[str_num].next=0;
+ str_data[str_num].func=NULL;
+ str_data[str_num].backpatch=-1;
+ str_data[str_num].label=-1;
+ str_pos+=strlen(p)+1;
+ return str_num++;
+}
+
+
+/*==========================================
+ * スクリプトバッファサイズの確認と拡張
+ *------------------------------------------
+ */
+static void check_script_buf(int size)
+{
+ if(script_pos+size>=script_size){
+ script_size+=SCRIPT_BLOCK_SIZE;
+ script_buf=(char *)aRealloc(script_buf,script_size);
+ memset(script_buf + script_size - SCRIPT_BLOCK_SIZE, '\0',
+ SCRIPT_BLOCK_SIZE);
+ }
+}
+
+/*==========================================
+ * スクリプトバッファに1バイト書き込む
+ *------------------------------------------
+ */
+static void add_scriptb(int a)
+{
+ check_script_buf(1);
+ script_buf[script_pos++]=a;
+}
+
+/*==========================================
+ * スクリプトバッファにデータタイプを書き込む
+ *------------------------------------------
+ */
+static void add_scriptc(int a)
+{
+ while(a>=0x40){
+ add_scriptb((a&0x3f)|0x40);
+ a=(a-0x40)>>6;
+ }
+ add_scriptb(a&0x3f);
+}
+
+/*==========================================
+ * スクリプトバッファに整数を書き込む
+ *------------------------------------------
+ */
+static void add_scripti(int a)
+{
+ while(a>=0x40){
+ add_scriptb(a|0xc0);
+ a=(a-0x40)>>6;
+ }
+ add_scriptb(a|0x80);
+}
+
+/*==========================================
+ * スクリプトバッファにラベル/変数/関数を書き込む
+ *------------------------------------------
+ */
+// 最大16Mまで
+static void add_scriptl(int l)
+{
+ int backpatch = str_data[l].backpatch;
+
+ switch(str_data[l].type){
+ case C_POS:
+ add_scriptc(C_POS);
+ add_scriptb(str_data[l].label);
+ add_scriptb(str_data[l].label>>8);
+ add_scriptb(str_data[l].label>>16);
+ break;
+ case C_NOP:
+ // ラベルの可能性があるのでbackpatch用データ埋め込み
+ add_scriptc(C_NAME);
+ str_data[l].backpatch=script_pos;
+ add_scriptb(backpatch);
+ add_scriptb(backpatch>>8);
+ add_scriptb(backpatch>>16);
+ break;
+ case C_INT:
+ add_scripti(str_data[l].val);
+ break;
+ default:
+ // もう他の用途と確定してるので数字をそのまま
+ add_scriptc(C_NAME);
+ add_scriptb(l);
+ add_scriptb(l>>8);
+ add_scriptb(l>>16);
+ break;
+ }
+}
+
+/*==========================================
+ * ラベルを解決する
+ *------------------------------------------
+ */
+void set_label(int l,int pos)
+{
+ int i,next;
+
+ str_data[l].type=C_POS;
+ str_data[l].label=pos;
+ for(i=str_data[l].backpatch;i>=0 && i!=0x00ffffff;){
+ next=(*(int*)(script_buf+i)) & 0x00ffffff;
+ script_buf[i-1]=C_POS;
+ script_buf[i]=pos;
+ script_buf[i+1]=pos>>8;
+ script_buf[i+2]=pos>>16;
+ i=next;
+ }
+}
+
+/*==========================================
+ * スペース/コメント読み飛ばし
+ *------------------------------------------
+ */
+static unsigned char *skip_space(unsigned char *p)
+{
+ while(1){
+ while(isspace(*p))
+ p++;
+ if(p[0]=='/' && p[1]=='/'){
+ while(*p && *p!='\n')
+ p++;
+ } else if(p[0]=='/' && p[1]=='*'){
+ p++;
+ while(*p && (p[-1]!='*' || p[0]!='/'))
+ p++;
+ if(*p) p++;
+ } else
+ break;
+ }
+ return p;
+}
+
+/*==========================================
+ * 1単語スキップ
+ *------------------------------------------
+ */
+static unsigned char *skip_word(unsigned char *p)
+{
+ // prefix
+ if(*p=='$') p++; // MAP鯖内共有変数用
+ if(*p=='@') p++; // 一時的変数用(like weiss)
+ if(*p=='#') p++; // account変数用
+ if(*p=='#') p++; // ワールドaccount変数用
+ if(*p=='l') p++; // 一時的変数用(like weiss)
+
+ while(isalnum(*p)||*p=='_'|| *p>=0x81)
+ if(*p>=0x81 && p[1]){
+ p+=2;
+ } else
+ p++;
+
+ // postfix
+ if(*p=='$') p++; // 文字列変数
+
+ return p;
+}
+
+static unsigned char *startptr;
+static int startline;
+
+/*==========================================
+ * エラーメッセージ出力
+ *------------------------------------------
+ */
+static void disp_error_message(const char *mes,const unsigned char *pos)
+{
+ int line,c=0,i;
+ unsigned char *p,*linestart,*lineend;
+
+ for(line=startline,p=startptr;p && *p;line++){
+ linestart=p;
+ lineend=strchr(p,'\n');
+ if(lineend){
+ c=*lineend;
+ *lineend=0;
+ }
+ if(lineend==NULL || pos<lineend){
+ printf("%s line %d : ",mes,line);
+ for(i=0;(linestart[i]!='\r') && (linestart[i]!='\n') && linestart[i];i++){
+ if(linestart+i!=pos)
+ printf("%c",linestart[i]);
+ else
+ printf("\'%c\'",linestart[i]);
+ }
+ printf("\a\n");
+ if(lineend)
+ *lineend=c;
+ return;
+ }
+ *lineend=c;
+ p=lineend+1;
+ }
+}
+
+/*==========================================
+ * 項の解析
+ *------------------------------------------
+ */
+unsigned char* parse_simpleexpr(unsigned char *p)
+{
+ int i;
+ p=skip_space(p);
+
+#ifdef DEBUG_FUNCIN
+ if(battle_config.etc_log)
+ printf("parse_simpleexpr %s\n",p);
+#endif
+ if(*p==';' || *p==','){
+ disp_error_message("unexpected expr end",p);
+ exit(1);
+ }
+ if(*p=='('){
+
+ p=parse_subexpr(p+1,-1);
+ p=skip_space(p);
+ if((*p++)!=')'){
+ disp_error_message("unmatch ')'",p);
+ exit(1);
+ }
+ } else if(isdigit(*p) || ((*p=='-' || *p=='+') && isdigit(p[1]))){
+ char *np;
+ i=strtoul(p,&np,0);
+ add_scripti(i);
+ p=np;
+ } else if(*p=='"'){
+ add_scriptc(C_STR);
+ p++;
+ while(*p && *p!='"'){
+ if(p[-1]<=0x7e && *p=='\\')
+ p++;
+ else if(*p=='\n'){
+ disp_error_message("unexpected newline @ string",p);
+ exit(1);
+ }
+ add_scriptb(*p++);
+ }
+ if(!*p){
+ disp_error_message("unexpected eof @ string",p);
+ exit(1);
+ }
+ add_scriptb(0);
+ p++; //'"'
+ } else {
+ int c,l;
+ char *p2;
+ // label , register , function etc
+ if(skip_word(p)==p){
+ disp_error_message("unexpected character",p);
+ exit(1);
+ }
+ p2=skip_word(p);
+ c=*p2; *p2=0; // 名前をadd_strする
+ l=add_str(p);
+
+ parse_cmd=l; // warn_*_mismatch_paramnumのために必要
+ if(l==search_str("if")) // warn_cmd_no_commaのために必要
+ parse_cmd_if++;
+/*
+ // 廃止予定のl14/l15,およびプレフィックスlの警告
+ if( strcmp(str_buf+str_data[l].str,"l14")==0 ||
+ strcmp(str_buf+str_data[l].str,"l15")==0 ){
+ disp_error_message("l14 and l15 is DEPRECATED. use @menu instead of l15.",p);
+ }else if(str_buf[str_data[l].str]=='l'){
+ disp_error_message("prefix 'l' is DEPRECATED. use prefix '@' instead.",p2);
+ }
+*/
+ *p2=c; p=p2;
+
+ if(str_data[l].type!=C_FUNC && c=='['){
+ // array(name[i] => getelementofarray(name,i) )
+ add_scriptl(search_str("getelementofarray"));
+ add_scriptc(C_ARG);
+ add_scriptl(l);
+ p=parse_subexpr(p+1,-1);
+ p=skip_space(p);
+ if((*p++)!=']'){
+ disp_error_message("unmatch ']'",p);
+ exit(1);
+ }
+ add_scriptc(C_FUNC);
+ }else
+ add_scriptl(l);
+
+ }
+
+#ifdef DEBUG_FUNCIN
+ if(battle_config.etc_log)
+ printf("parse_simpleexpr end %s\n",p);
+#endif
+ return p;
+}
+
+/*==========================================
+ * 式の解析
+ *------------------------------------------
+ */
+unsigned char* parse_subexpr(unsigned char *p,int limit)
+{
+ int op,opl,len;
+ char *tmpp;
+
+#ifdef DEBUG_FUNCIN
+ if(battle_config.etc_log)
+ printf("parse_subexpr %s\n",p);
+#endif
+ p=skip_space(p);
+
+ if(*p=='-'){
+ tmpp=skip_space(p+1);
+ if(*tmpp==';' || *tmpp==','){
+ add_scriptl(LABEL_NEXTLINE);
+ p++;
+ return p;
+ }
+ }
+ tmpp=p;
+ if((op=C_NEG,*p=='-') || (op=C_LNOT,*p=='!') || (op=C_NOT,*p=='~')){
+ p=parse_subexpr(p+1,100);
+ add_scriptc(op);
+ } else
+ p=parse_simpleexpr(p);
+ p=skip_space(p);
+ while(((op=C_ADD,opl=6,len=1,*p=='+') ||
+ (op=C_SUB,opl=6,len=1,*p=='-') ||
+ (op=C_MUL,opl=7,len=1,*p=='*') ||
+ (op=C_DIV,opl=7,len=1,*p=='/') ||
+ (op=C_MOD,opl=7,len=1,*p=='%') ||
+ (op=C_FUNC,opl=8,len=1,*p=='(') ||
+ (op=C_LAND,opl=1,len=2,*p=='&' && p[1]=='&') ||
+ (op=C_AND,opl=5,len=1,*p=='&') ||
+ (op=C_LOR,opl=0,len=2,*p=='|' && p[1]=='|') ||
+ (op=C_OR,opl=4,len=1,*p=='|') ||
+ (op=C_XOR,opl=3,len=1,*p=='^') ||
+ (op=C_EQ,opl=2,len=2,*p=='=' && p[1]=='=') ||
+ (op=C_NE,opl=2,len=2,*p=='!' && p[1]=='=') ||
+ (op=C_R_SHIFT,opl=5,len=2,*p=='>' && p[1]=='>') ||
+ (op=C_GE,opl=2,len=2,*p=='>' && p[1]=='=') ||
+ (op=C_GT,opl=2,len=1,*p=='>') ||
+ (op=C_L_SHIFT,opl=5,len=2,*p=='<' && p[1]=='<') ||
+ (op=C_LE,opl=2,len=2,*p=='<' && p[1]=='=') ||
+ (op=C_LT,opl=2,len=1,*p=='<')) && opl>limit){
+ p+=len;
+ if(op==C_FUNC){
+ int i=0,func=parse_cmd;
+ const char *plist[128];
+
+ if( str_data[func].type!=C_FUNC ){
+ disp_error_message("expect function",tmpp);
+ exit(0);
+ }
+
+ add_scriptc(C_ARG);
+ do {
+ plist[i]=p;
+ p=parse_subexpr(p,-1);
+ p=skip_space(p);
+ if(*p==',') p++;
+ else if(*p!=')' && script_config.warn_func_no_comma){
+ disp_error_message("expect ',' or ')' at func params",p);
+ }
+ p=skip_space(p);
+ i++;
+ } while(*p && *p!=')' && i<128);
+ plist[i]=p;
+ if(*(p++)!=')'){
+ disp_error_message("func request '(' ')'",p);
+ exit(1);
+ }
+
+ if( str_data[func].type==C_FUNC && script_config.warn_func_mismatch_paramnum){
+ const char *arg=buildin_func[str_data[func].val].arg;
+ int j=0;
+ for(j=0;arg[j];j++) if(arg[j]=='*')break;
+ if( (arg[j]==0 && i!=j) || (arg[j]=='*' && i<j) ){
+ disp_error_message("illegal number of parameters",plist[(i<j)?i:j]);
+ }
+ }
+ } else {
+ p=parse_subexpr(p,opl);
+ }
+ add_scriptc(op);
+ p=skip_space(p);
+ }
+#ifdef DEBUG_FUNCIN
+ if(battle_config.etc_log)
+ printf("parse_subexpr end %s\n",p);
+#endif
+ return p; /* return first untreated operator */
+}
+
+/*==========================================
+ * 式の評価
+ *------------------------------------------
+ */
+unsigned char* parse_expr(unsigned char *p)
+{
+#ifdef DEBUG_FUNCIN
+ if(battle_config.etc_log)
+ printf("parse_expr %s\n",p);
+#endif
+ switch(*p){
+ case ')': case ';': case ':': case '[': case ']':
+ case '}':
+ disp_error_message("unexpected char",p);
+ exit(1);
+ }
+ p=parse_subexpr(p,-1);
+#ifdef DEBUG_FUNCIN
+ if(battle_config.etc_log)
+ printf("parse_expr end %s\n",p);
+#endif
+ return p;
+}
+
+/*==========================================
+ * 行の解析
+ *------------------------------------------
+ */
+unsigned char* parse_line(unsigned char *p)
+{
+ int i=0,cmd;
+ const char *plist[128];
+ char *p2;
+
+ p=skip_space(p);
+ if(*p==';')
+ return p;
+
+ parse_cmd_if=0; // warn_cmd_no_commaのために必要
+
+ // 最初は関数名
+ p2=p;
+ p=parse_simpleexpr(p);
+ p=skip_space(p);
+
+ cmd=parse_cmd;
+ if( str_data[cmd].type!=C_FUNC ){
+ disp_error_message("expect command",p2);
+// exit(0);
+ }
+
+ add_scriptc(C_ARG);
+ while(p && *p && *p!=';' && i<128){
+ plist[i]=p;
+
+ p=parse_expr(p);
+ p=skip_space(p);
+ // 引数区切りの,処理
+ if(*p==',') p++;
+ else if(*p!=';' && script_config.warn_cmd_no_comma && parse_cmd_if*2<=i ){
+ disp_error_message("expect ',' or ';' at cmd params",p);
+ }
+ p=skip_space(p);
+ i++;
+ }
+ plist[i]=p;
+ if(!p || *(p++)!=';'){
+ disp_error_message("need ';'",p);
+ exit(1);
+ }
+ add_scriptc(C_FUNC);
+
+ if( str_data[cmd].type==C_FUNC && script_config.warn_cmd_mismatch_paramnum){
+ const char *arg=buildin_func[str_data[cmd].val].arg;
+ int j=0;
+ for(j=0;arg[j];j++) if(arg[j]=='*')break;
+ if( (arg[j]==0 && i!=j) || (arg[j]=='*' && i<j) ){
+ disp_error_message("illegal number of parameters",plist[(i<j)?i:j]);
+ }
+ }
+
+
+ return p;
+}
+
+/*==========================================
+ * 組み込み関数の追加
+ *------------------------------------------
+ */
+static void add_buildin_func(void)
+{
+ int i,n;
+ for(i=0;buildin_func[i].func;i++){
+ n=add_str(buildin_func[i].name);
+ str_data[n].type=C_FUNC;
+ str_data[n].val=i;
+ str_data[n].func=buildin_func[i].func;
+ }
+}
+
+/*==========================================
+ * 定数データベースの読み込み
+ *------------------------------------------
+ */
+static void read_constdb(void)
+{
+ FILE *fp;
+ char line[1024],name[1024];
+ int val,n,i,type;
+
+ fp=fopen("db/const.txt","r");
+ if(fp==NULL){
+ printf("can't read db/const.txt\n");
+ return ;
+ }
+ while(fgets(line,1020,fp)){
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ type=0;
+ if(sscanf(line,"%[A-Za-z0-9_],%d,%d",name,&val,&type)>=2 ||
+ sscanf(line,"%[A-Za-z0-9_] %d %d",name,&val,&type)>=2){
+ for(i=0;name[i];i++)
+ name[i]=tolower(name[i]);
+ n=add_str(name);
+ if(type==0)
+ str_data[n].type=C_INT;
+ else
+ str_data[n].type=C_PARAM;
+ str_data[n].val=val;
+ }
+ }
+ fclose(fp);
+}
+
+/*==========================================
+ * スクリプトの解析
+ *------------------------------------------
+ */
+unsigned char* parse_script(unsigned char *src,int line)
+{
+ unsigned char *p,*tmpp;
+ int i;
+ static int first=1;
+
+ if(first){
+ add_buildin_func();
+ read_constdb();
+ }
+ first=0;
+ script_buf=(unsigned char *)aCalloc(SCRIPT_BLOCK_SIZE,sizeof(unsigned char));
+ script_pos=0;
+ script_size=SCRIPT_BLOCK_SIZE;
+ str_data[LABEL_NEXTLINE].type=C_NOP;
+ str_data[LABEL_NEXTLINE].backpatch=-1;
+ str_data[LABEL_NEXTLINE].label=-1;
+ for(i=LABEL_START;i<str_num;i++){
+ if(str_data[i].type==C_POS || str_data[i].type==C_NAME){
+ str_data[i].type=C_NOP;
+ str_data[i].backpatch=-1;
+ str_data[i].label=-1;
+ }
+ }
+
+ // 外部用label dbの初期化
+ if(scriptlabel_db!=NULL)
+ strdb_final(scriptlabel_db,scriptlabel_final);
+ scriptlabel_db=strdb_init(50);
+
+ // for error message
+ startptr = src;
+ startline = line;
+
+ p=src;
+ p=skip_space(p);
+ if(*p!='{'){
+ disp_error_message("not found '{'",p);
+ return NULL;
+ }
+ for(p++;p && *p && *p!='}';){
+ p=skip_space(p);
+ // labelだけ特殊処理
+ tmpp=skip_space(skip_word(p));
+ if(*tmpp==':'){
+ int l,c;
+
+ c=*skip_word(p);
+ *skip_word(p)=0;
+ l=add_str(p);
+ if(str_data[l].label!=-1){
+ *skip_word(p)=c;
+ disp_error_message("dup label ",p);
+ exit(1);
+ }
+ set_label(l,script_pos);
+ strdb_insert(scriptlabel_db,p,script_pos); // 外部用label db登録
+ *skip_word(p)=c;
+ p=tmpp+1;
+ continue;
+ }
+
+ // 他は全部一緒くた
+ p=parse_line(p);
+ p=skip_space(p);
+ add_scriptc(C_EOL);
+
+ set_label(LABEL_NEXTLINE,script_pos);
+ str_data[LABEL_NEXTLINE].type=C_NOP;
+ str_data[LABEL_NEXTLINE].backpatch=-1;
+ str_data[LABEL_NEXTLINE].label=-1;
+ }
+
+ add_scriptc(C_NOP);
+
+ script_size = script_pos;
+ script_buf=(char *)aRealloc(script_buf,script_pos + 1);
+
+ // 未解決のラベルを解決
+ for(i=LABEL_START;i<str_num;i++){
+ if(str_data[i].type==C_NOP){
+ int j,next;
+ str_data[i].type=C_NAME;
+ str_data[i].label=i;
+ for(j=str_data[i].backpatch;j>=0 && j!=0x00ffffff;){
+ next=(*(int*)(script_buf+j)) & 0x00ffffff;
+ script_buf[j]=i;
+ script_buf[j+1]=i>>8;
+ script_buf[j+2]=i>>16;
+ j=next;
+ }
+ }
+ }
+
+#ifdef DEBUG_DISP
+ for(i=0;i<script_pos;i++){
+ if((i&15)==0) printf("%04x : ",i);
+ printf("%02x ",script_buf[i]);
+ if((i&15)==15) printf("\n");
+ }
+ printf("\n");
+#endif
+
+ return script_buf;
+}
+
+//
+// 実行系
+//
+enum {STOP=1,END,RERUNLINE,GOTO,RETFUNC};
+
+/*==========================================
+ * ridからsdへの解決
+ *------------------------------------------
+ */
+struct map_session_data *script_rid2sd(struct script_state *st)
+{
+ struct map_session_data *sd=map_id2sd(st->rid);
+ if(!sd){
+ printf("script_rid2sd: fatal error ! player not attached!\n");
+ }
+ return sd;
+}
+
+
+/*==========================================
+ * 変数の読み取り
+ *------------------------------------------
+ */
+int get_val(struct script_state*st,struct script_data* data)
+{
+ struct map_session_data *sd=NULL;
+ if(data->type==C_NAME){
+ char *name=str_buf+str_data[data->u.num&0x00ffffff].str;
+ char prefix=*name;
+ char postfix=name[strlen(name)-1];
+
+ if(prefix!='$'){
+ if((sd=script_rid2sd(st))==NULL)
+ printf("get_val error name?:%s\n",name);
+ }
+ if(postfix=='$'){
+
+ data->type=C_CONSTSTR;
+ if( prefix=='@' || prefix=='l' ){
+ if(sd)
+ data->u.str = pc_readregstr(sd,data->u.num);
+ }else if(prefix=='$'){
+ data->u.str = (char *)numdb_search(mapregstr_db,data->u.num);
+ }else{
+ printf("script: get_val: illegal scope string variable.\n");
+ data->u.str = "!!ERROR!!";
+ }
+ if( data->u.str == NULL )
+ data->u.str ="";
+
+ }else{
+
+ data->type=C_INT;
+ if(str_data[data->u.num&0x00ffffff].type==C_INT){
+ data->u.num = str_data[data->u.num&0x00ffffff].val;
+ }else if(str_data[data->u.num&0x00ffffff].type==C_PARAM){
+ if(sd)
+ data->u.num = pc_readparam(sd,str_data[data->u.num&0x00ffffff].val);
+ }else if(prefix=='@' || prefix=='l'){
+ if(sd)
+ data->u.num = pc_readreg(sd,data->u.num);
+ }else if(prefix=='$'){
+ data->u.num = (int)numdb_search(mapreg_db,data->u.num);
+ }else if(prefix=='#'){
+ if( name[1]=='#'){
+ if(sd)
+ data->u.num = pc_readaccountreg2(sd,name);
+ }else{
+ if(sd)
+ data->u.num = pc_readaccountreg(sd,name);
+ }
+ }else{
+ if(sd)
+ data->u.num = pc_readglobalreg(sd,name);
+ }
+ }
+ }
+ return 0;
+}
+/*==========================================
+ * 変数の読み取り2
+ *------------------------------------------
+ */
+void* get_val2(struct script_state*st,int num)
+{
+ struct script_data dat;
+ dat.type=C_NAME;
+ dat.u.num=num;
+ get_val(st,&dat);
+ if( dat.type==C_INT ) return (void*)dat.u.num;
+ else return (void*)dat.u.str;
+}
+
+/*==========================================
+ * 変数設定用
+ *------------------------------------------
+ */
+static int set_reg(struct map_session_data *sd,int num,char *name,void *v)
+{
+ char prefix=*name;
+ char postfix=name[strlen(name)-1];
+
+ if( postfix=='$' ){
+ char *str=(char*)v;
+ if( prefix=='@' || prefix=='l'){
+ pc_setregstr(sd,num,str);
+ }else if(prefix=='$') {
+ mapreg_setregstr(num,str);
+ }else{
+ printf("script: set_reg: illegal scope string variable !");
+ }
+ }else{
+ // 数値
+ int val = (int)v;
+ if(str_data[num&0x00ffffff].type==C_PARAM){
+ pc_setparam(sd,str_data[num&0x00ffffff].val,val);
+ }else if(prefix=='@' || prefix=='l') {
+ pc_setreg(sd,num,val);
+ }else if(prefix=='$') {
+ mapreg_setreg(num,val);
+ }else if(prefix=='#') {
+ if( name[1]=='#' )
+ pc_setaccountreg2(sd,name,val);
+ else
+ pc_setaccountreg(sd,name,val);
+ }else{
+ pc_setglobalreg(sd,name,val);
+ }
+ }
+ return 0;
+}
+
+/*==========================================
+ * 文字列への変換
+ *------------------------------------------
+ */
+char* conv_str(struct script_state *st,struct script_data *data)
+{
+ get_val(st,data);
+ if(data->type==C_INT){
+ char *buf;
+ buf=(char *)aCalloc(16,sizeof(char));
+ sprintf(buf,"%d",data->u.num);
+ data->type=C_STR;
+ data->u.str=buf;
+#if 1
+ } else if(data->type==C_NAME){
+ // テンポラリ。本来無いはず
+ data->type=C_CONSTSTR;
+ data->u.str=str_buf+str_data[data->u.num].str;
+#endif
+ }
+ return data->u.str;
+}
+
+/*==========================================
+ * 数値へ変換
+ *------------------------------------------
+ */
+int conv_num(struct script_state *st,struct script_data *data)
+{
+ char *p;
+ get_val(st,data);
+ if(data->type==C_STR || data->type==C_CONSTSTR){
+ p=data->u.str;
+ data->u.num = atoi(p);
+ if(data->type==C_STR)
+ free(p);
+ data->type=C_INT;
+ }
+ return data->u.num;
+}
+
+/*==========================================
+ * スタックへ数値をプッシュ
+ *------------------------------------------
+ */
+void push_val(struct script_stack *stack,int type,int val)
+{
+ if(stack->sp >= stack->sp_max){
+ stack->sp_max += 64;
+ stack->stack_data = (struct script_data *)aRealloc(stack->stack_data,
+ sizeof(stack->stack_data[0]) * stack->sp_max);
+ memset(stack->stack_data + (stack->sp_max - 64), 0,
+ 64 * sizeof(*(stack->stack_data)));
+ }
+// if(battle_config.etc_log)
+// printf("push (%d,%d)-> %d\n",type,val,stack->sp);
+ stack->stack_data[stack->sp].type=type;
+ stack->stack_data[stack->sp].u.num=val;
+ stack->sp++;
+}
+
+/*==========================================
+ * スタックへ文字列をプッシュ
+ *------------------------------------------
+ */
+void push_str(struct script_stack *stack,int type,unsigned char *str)
+{
+ if(stack->sp>=stack->sp_max){
+ stack->sp_max += 64;
+ stack->stack_data = (struct script_data *)aRealloc(stack->stack_data,
+ sizeof(stack->stack_data[0]) * stack->sp_max);
+ memset(stack->stack_data + (stack->sp_max - 64), '\0',
+ 64 * sizeof(*(stack->stack_data)));
+ }
+// if(battle_config.etc_log)
+// printf("push (%d,%x)-> %d\n",type,str,stack->sp);
+ stack->stack_data[stack->sp].type=type;
+ stack->stack_data[stack->sp].u.str=str;
+ stack->sp++;
+}
+
+/*==========================================
+ * スタックへ複製をプッシュ
+ *------------------------------------------
+ */
+void push_copy(struct script_stack *stack,int pos)
+{
+ switch(stack->stack_data[pos].type){
+ case C_CONSTSTR:
+ push_str(stack,C_CONSTSTR,stack->stack_data[pos].u.str);
+ break;
+ case C_STR:
+ push_str(stack,C_STR,strdup(stack->stack_data[pos].u.str));
+ break;
+ default:
+ push_val(stack,stack->stack_data[pos].type,stack->stack_data[pos].u.num);
+ break;
+ }
+}
+
+/*==========================================
+ * スタックからポップ
+ *------------------------------------------
+ */
+void pop_stack(struct script_stack* stack,int start,int end)
+{
+ int i;
+ for(i=start;i<end;i++){
+ if(stack->stack_data[i].type==C_STR){
+ free(stack->stack_data[i].u.str);
+ }
+ }
+ if(stack->sp>end){
+ memmove(&stack->stack_data[start],&stack->stack_data[end],sizeof(stack->stack_data[0])*(stack->sp-end));
+ }
+ stack->sp-=end-start;
+}
+
+//
+// 埋め込み関数
+//
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_mes(struct script_state *st)
+{
+ conv_str(st,& (st->stack->stack_data[st->start+2]));
+ clif_scriptmes(script_rid2sd(st),st->oid,st->stack->stack_data[st->start+2].u.str);
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_goto(struct script_state *st)
+{
+ int pos;
+
+ if( st->stack->stack_data[st->start+2].type!=C_POS ){
+ printf("script: goto: not label !\n");
+ st->state=END;
+ return 0;
+ }
+
+ pos=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ st->pos=pos;
+ st->state=GOTO;
+ return 0;
+}
+
+/*==========================================
+ * ユーザー定義関数の呼び出し
+ *------------------------------------------
+ */
+int buildin_callfunc(struct script_state *st)
+{
+ char *scr;
+ char *str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+
+ if( (scr=strdb_search(script_get_userfunc_db(),str)) ){
+ int i,j;
+ for(i=st->start+3,j=0;i<st->end;i++,j++)
+ push_copy(st->stack,i);
+
+ push_val(st->stack,C_INT,j); // 引数の数をプッシュ
+ push_val(st->stack,C_INT,st->defsp); // 現在の基準スタックポインタをプッシュ
+ push_val(st->stack,C_INT,(int)st->script); // 現在のスクリプトをプッシュ
+ push_val(st->stack,C_RETINFO,st->pos); // 現在のスクリプト位置をプッシュ
+
+ st->pos=0;
+ st->script=scr;
+ st->defsp=st->start+4+j;
+ st->state=GOTO;
+ }else{
+ printf("script:callfunc: function not found! [%s]\n",str);
+ st->state=END;
+ }
+ return 0;
+}
+/*==========================================
+ * サブルーティンの呼び出し
+ *------------------------------------------
+ */
+int buildin_callsub(struct script_state *st)
+{
+ int pos=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ int i,j;
+ for(i=st->start+3,j=0;i<st->end;i++,j++)
+ push_copy(st->stack,i);
+
+ push_val(st->stack,C_INT,j); // 引数の数をプッシュ
+ push_val(st->stack,C_INT,st->defsp); // 現在の基準スタックポインタをプッシュ
+ push_val(st->stack,C_INT,(int)st->script); // 現在のスクリプトをプッシュ
+ push_val(st->stack,C_RETINFO,st->pos); // 現在のスクリプト位置をプッシュ
+
+ st->pos=pos;
+ st->defsp=st->start+4+j;
+ st->state=GOTO;
+ return 0;
+}
+
+/*==========================================
+ * 引数の所得
+ *------------------------------------------
+ */
+int buildin_getarg(struct script_state *st)
+{
+ int num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ int max,stsp;
+ if( st->defsp<4 || st->stack->stack_data[st->defsp-1].type!=C_RETINFO ){
+ printf("script:getarg without callfunc or callsub!\n");
+ st->state=END;
+ return 0;
+ }
+ max=conv_num(st,& (st->stack->stack_data[st->defsp-4]));
+ stsp=st->defsp - max -4;
+ if( num >= max ){
+ printf("script:getarg arg1(%d) out of range(%d) !\n",num,max);
+ st->state=END;
+ return 0;
+ }
+ push_copy(st->stack,stsp+num);
+ return 0;
+}
+
+/*==========================================
+ * サブルーチン/ユーザー定義関数の終了
+ *------------------------------------------
+ */
+int buildin_return(struct script_state *st)
+{
+ if(st->end>st->start+2){ // 戻り値有り
+ push_copy(st->stack,st->start+2);
+ }
+ st->state=RETFUNC;
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_next(struct script_state *st)
+{
+ st->state=STOP;
+ clif_scriptnext(script_rid2sd(st),st->oid);
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_close(struct script_state *st)
+{
+ st->state=END;
+ clif_scriptclose(script_rid2sd(st),st->oid);
+ return 0;
+}
+int buildin_close2(struct script_state *st)
+{
+ st->state=STOP;
+ clif_scriptclose(script_rid2sd(st),st->oid);
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_menu(struct script_state *st)
+{
+ char *buf;
+ int len,i;
+ struct map_session_data *sd;
+
+ sd=script_rid2sd(st);
+
+ if(sd->state.menu_or_input==0){
+ st->state=RERUNLINE;
+ sd->state.menu_or_input=1;
+ for(i=st->start+2,len=16;i<st->end;i+=2){
+ conv_str(st,& (st->stack->stack_data[i]));
+ len+=strlen(st->stack->stack_data[i].u.str)+1;
+ }
+ buf=(char *)aCalloc(len,sizeof(char));
+ buf[0]=0;
+ for(i=st->start+2,len=0;i<st->end;i+=2){
+ strcat(buf,st->stack->stack_data[i].u.str);
+ strcat(buf,":");
+ }
+ clif_scriptmenu(script_rid2sd(st),st->oid,buf);
+ free(buf);
+ } else if(sd->npc_menu==0xff){ // cansel
+ sd->state.menu_or_input=0;
+ st->state=END;
+ } else { // goto動作
+ // ragemu互換のため
+ pc_setreg(sd,add_str("l15"),sd->npc_menu);
+ pc_setreg(sd,add_str("@menu"),sd->npc_menu);
+ sd->state.menu_or_input=0;
+ if(sd->npc_menu>0 && sd->npc_menu<(st->end-st->start)/2){
+ int pos;
+ if( st->stack->stack_data[st->start+sd->npc_menu*2+1].type!=C_POS ){
+ printf("script: menu: not label !\n");
+ st->state=END;
+ return 0;
+ }
+ pos=conv_num(st,& (st->stack->stack_data[st->start+sd->npc_menu*2+1]));
+ st->pos=pos;
+ st->state=GOTO;
+ }
+ }
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_rand(struct script_state *st)
+{
+ int range,min,max;
+
+ if(st->end>st->start+3){
+ min=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ max=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ if(max<min){
+ int tmp;
+ tmp=min;
+ min=max;
+ max=tmp;
+ }
+ range=max-min+1;
+ push_val(st->stack,C_INT,rand()%range+min);
+ } else {
+ range=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ push_val(st->stack,C_INT,rand()%range);
+ }
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_warp(struct script_state *st)
+{
+ int x,y;
+ char *str;
+ struct map_session_data *sd=script_rid2sd(st);
+
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ x=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ y=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ if(strcmp(str,"Random")==0)
+ pc_randomwarp(sd,3);
+ else if(strcmp(str,"SavePoint")==0){
+ if(map[sd->bl.m].flag.noreturn) // 蝶禁止
+ return 0;
+
+ pc_setpos(sd,sd->status.save_point.map,
+ sd->status.save_point.x,sd->status.save_point.y,3);
+ }else if(strcmp(str,"Save")==0){
+ if(map[sd->bl.m].flag.noreturn) // 蝶禁止
+ return 0;
+
+ pc_setpos(sd,sd->status.save_point.map,
+ sd->status.save_point.x,sd->status.save_point.y,3);
+ }else
+ pc_setpos(sd,str,x,y,0);
+ return 0;
+}
+/*==========================================
+ * エリア指定ワープ
+ *------------------------------------------
+ */
+int buildin_areawarp_sub(struct block_list *bl,va_list ap)
+{
+ int x,y;
+ char *map;
+ map=va_arg(ap, char *);
+ x=va_arg(ap,int);
+ y=va_arg(ap,int);
+ if(strcmp(map,"Random")==0)
+ pc_randomwarp((struct map_session_data *)bl,3);
+ else
+ pc_setpos((struct map_session_data *)bl,map,x,y,0);
+ return 0;
+}
+int buildin_areawarp(struct script_state *st)
+{
+ int x,y,m;
+ char *str;
+ char *mapname;
+ int x0,y0,x1,y1;
+
+ mapname=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ x0=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ y0=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ x1=conv_num(st,& (st->stack->stack_data[st->start+5]));
+ y1=conv_num(st,& (st->stack->stack_data[st->start+6]));
+ str=conv_str(st,& (st->stack->stack_data[st->start+7]));
+ x=conv_num(st,& (st->stack->stack_data[st->start+8]));
+ y=conv_num(st,& (st->stack->stack_data[st->start+9]));
+
+ if( (m=map_mapname2mapid(mapname))< 0)
+ return 0;
+
+ map_foreachinarea(buildin_areawarp_sub,
+ m,x0,y0,x1,y1,BL_PC, str,x,y );
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_heal(struct script_state *st)
+{
+ int hp,sp;
+
+ hp=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sp=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ pc_heal(script_rid2sd(st),hp,sp);
+ return 0;
+}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_itemheal(struct script_state *st)
+{
+ int hp,sp;
+
+ hp=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sp=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ pc_itemheal(script_rid2sd(st),hp,sp);
+ return 0;
+}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_percentheal(struct script_state *st)
+{
+ int hp,sp;
+
+ hp=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sp=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ pc_percentheal(script_rid2sd(st),hp,sp);
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_jobchange(struct script_state *st)
+{
+ int job, upper=-1;
+
+ job=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ if( st->end>st->start+3 )
+ upper=conv_num(st,& (st->stack->stack_data[st->start+3]));
+
+ if ((job >= 0 && job < MAX_PC_CLASS))
+ pc_jobchange(script_rid2sd(st),job, upper);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_input(struct script_state *st)
+{
+ struct map_session_data *sd=NULL;
+ int num=(st->end>st->start+2)?st->stack->stack_data[st->start+2].u.num:0;
+ char *name=(st->end>st->start+2)?str_buf+str_data[num&0x00ffffff].str:"";
+// char prefix=*name;
+ char postfix=name[strlen(name)-1];
+
+ sd=script_rid2sd(st);
+ if(sd->state.menu_or_input){
+ sd->state.menu_or_input=0;
+ if( postfix=='$' ){
+ // 文字列
+ if(st->end>st->start+2){ // 引数1個
+ set_reg(sd,num,name,(void*)sd->npc_str);
+ }else{
+ printf("buildin_input: string discarded !!\n");
+ }
+ }else{
+
+ //commented by Lupus (check Value Number Input fix in clif.c)
+ //** Fix by fritz :X keeps people from abusing old input bugs
+ if(sd->npc_amount < 0) //** If input amount is less then 0
+ {
+ clif_tradecancelled(sd); // added "Deal has been cancelled" message by Valaris
+ buildin_close(st); //** close
+ }
+
+ // 数値
+ if(st->end>st->start+2){ // 引数1個
+ set_reg(sd,num,name,(void*)sd->npc_amount);
+ } else {
+ // ragemu互換のため
+ pc_setreg(sd,add_str("l14"),sd->npc_amount);
+ }
+ }
+ } else {
+ st->state=RERUNLINE;
+ if(postfix=='$')clif_scriptinputstr(sd,st->oid);
+ else clif_scriptinput(sd,st->oid);
+ sd->state.menu_or_input=1;
+ }
+ return 0;
+}
+
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_if(struct script_state *st)
+{
+ int sel,i;
+
+ sel=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ if(!sel)
+ return 0;
+
+ // 関数名をコピー
+ push_copy(st->stack,st->start+3);
+ // 間に引数マーカを入れて
+ push_val(st->stack,C_ARG,0);
+ // 残りの引数をコピー
+ for(i=st->start+4;i<st->end;i++){
+ push_copy(st->stack,i);
+ }
+ run_func(st);
+
+ return 0;
+}
+
+
+/*==========================================
+ * 変数設定
+ *------------------------------------------
+ */
+int buildin_set(struct script_state *st)
+{
+ struct map_session_data *sd=NULL;
+ int num=st->stack->stack_data[st->start+2].u.num;
+ char *name=str_buf+str_data[num&0x00ffffff].str;
+ char prefix=*name;
+ char postfix=name[strlen(name)-1];
+
+ if( st->stack->stack_data[st->start+2].type!=C_NAME ){
+ printf("script: buildin_set: not name\n");
+ return 0;
+ }
+
+ if( prefix!='$' )
+ sd=script_rid2sd(st);
+
+
+ if( postfix=='$' ){
+ // 文字列
+ char *str = conv_str(st,& (st->stack->stack_data[st->start+3]));
+ set_reg(sd,num,name,(void*)str);
+ }else{
+ // 数値
+ int val = conv_num(st,& (st->stack->stack_data[st->start+3]));
+ set_reg(sd,num,name,(void*)val);
+ }
+
+ return 0;
+}
+/*==========================================
+ * 配列変数設定
+ *------------------------------------------
+ */
+int buildin_setarray(struct script_state *st)
+{
+ struct map_session_data *sd=NULL;
+ int num=st->stack->stack_data[st->start+2].u.num;
+ char *name=str_buf+str_data[num&0x00ffffff].str;
+ char prefix=*name;
+ char postfix=name[strlen(name)-1];
+ int i,j;
+
+ if( prefix!='$' && prefix!='@' ){
+ printf("buildin_setarray: illegal scope !\n");
+ return 0;
+ }
+ if( prefix!='$' )
+ sd=script_rid2sd(st);
+
+ for(j=0,i=st->start+3; i<st->end && j<128;i++,j++){
+ void *v;
+ if( postfix=='$' )
+ v=(void*)conv_str(st,& (st->stack->stack_data[i]));
+ else
+ v=(void*)conv_num(st,& (st->stack->stack_data[i]));
+ set_reg( sd, num+(j<<24), name, v);
+ }
+ return 0;
+}
+/*==========================================
+ * 配列変数クリア
+ *------------------------------------------
+ */
+int buildin_cleararray(struct script_state *st)
+{
+ struct map_session_data *sd=NULL;
+ int num=st->stack->stack_data[st->start+2].u.num;
+ char *name=str_buf+str_data[num&0x00ffffff].str;
+ char prefix=*name;
+ char postfix=name[strlen(name)-1];
+ int sz=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ int i;
+ void *v;
+
+ if( prefix!='$' && prefix!='@' ){
+ printf("buildin_cleararray: illegal scope !\n");
+ return 0;
+ }
+ if( prefix!='$' )
+ sd=script_rid2sd(st);
+
+ if( postfix=='$' )
+ v=(void*)conv_str(st,& (st->stack->stack_data[st->start+3]));
+ else
+ v=(void*)conv_num(st,& (st->stack->stack_data[st->start+3]));
+
+ for(i=0;i<sz;i++)
+ set_reg(sd,num+(i<<24),name,v);
+ return 0;
+}
+/*==========================================
+ * 配列変数コピー
+ *------------------------------------------
+ */
+int buildin_copyarray(struct script_state *st)
+{
+ struct map_session_data *sd=NULL;
+ int num=st->stack->stack_data[st->start+2].u.num;
+ char *name=str_buf+str_data[num&0x00ffffff].str;
+ char prefix=*name;
+ char postfix=name[strlen(name)-1];
+ int num2=st->stack->stack_data[st->start+3].u.num;
+ char *name2=str_buf+str_data[num2&0x00ffffff].str;
+ char prefix2=*name2;
+ char postfix2=name2[strlen(name2)-1];
+ int sz=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ int i;
+
+ if( prefix!='$' && prefix!='@' && prefix2!='$' && prefix2!='@' ){
+ printf("buildin_copyarray: illegal scope !\n");
+ return 0;
+ }
+ if( (postfix=='$' || postfix2=='$') && postfix!=postfix2 ){
+ printf("buildin_copyarray: type mismatch !\n");
+ return 0;
+ }
+ if( prefix!='$' || prefix2!='$' )
+ sd=script_rid2sd(st);
+
+
+ for(i=0;i<sz;i++)
+ set_reg(sd,num+(i<<24),name, get_val2(st,num2+(i<<24)) );
+ return 0;
+}
+/*==========================================
+ * 配列変数のサイズ所得
+ *------------------------------------------
+ */
+static int getarraysize(struct script_state *st,int num,int postfix)
+{
+ int i=(num>>24),c=i;
+ for(;i<128;i++){
+ void *v=get_val2(st,num+(i<<24));
+ if(postfix=='$' && *((char*)v) ) c=i;
+ if(postfix!='$' && (int)v )c=i;
+ }
+ return c+1;
+}
+int buildin_getarraysize(struct script_state *st)
+{
+ int num=st->stack->stack_data[st->start+2].u.num;
+ char *name=str_buf+str_data[num&0x00ffffff].str;
+ char prefix=*name;
+ char postfix=name[strlen(name)-1];
+
+ if( prefix!='$' && prefix!='@' ){
+ printf("buildin_copyarray: illegal scope !\n");
+ return 0;
+ }
+
+ push_val(st->stack,C_INT,getarraysize(st,num,postfix) );
+ return 0;
+}
+/*==========================================
+ * 配列変数から要素削除
+ *------------------------------------------
+ */
+int buildin_deletearray(struct script_state *st)
+{
+ struct map_session_data *sd=NULL;
+ int num=st->stack->stack_data[st->start+2].u.num;
+ char *name=str_buf+str_data[num&0x00ffffff].str;
+ char prefix=*name;
+ char postfix=name[strlen(name)-1];
+ int count=1;
+ int i,sz=getarraysize(st,num,postfix)-(num>>24)-count+1;
+
+
+ if( (st->end > st->start+3) )
+ count=conv_num(st,& (st->stack->stack_data[st->start+3]));
+
+ if( prefix!='$' && prefix!='@' ){
+ printf("buildin_deletearray: illegal scope !\n");
+ return 0;
+ }
+ if( prefix!='$' )
+ sd=script_rid2sd(st);
+
+ for(i=0;i<sz;i++){
+ set_reg(sd,num+(i<<24),name, get_val2(st,num+((i+count)<<24) ) );
+ }
+ for(;i<(128-(num>>24));i++){
+ if( postfix!='$' ) set_reg(sd,num+(i<<24),name, 0);
+ if( postfix=='$' ) set_reg(sd,num+(i<<24),name, "");
+ }
+ return 0;
+}
+
+/*==========================================
+ * 指定要素を表す値(キー)を所得する
+ *------------------------------------------
+ */
+int buildin_getelementofarray(struct script_state *st)
+{
+ if( st->stack->stack_data[st->start+2].type==C_NAME ){
+ int i=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ if(i>127 || i<0){
+ printf("script: getelementofarray (operator[]): param2 illegal number %d\n",i);
+ push_val(st->stack,C_INT,0);
+ }else{
+ push_val(st->stack,C_NAME,
+ (i<<24) | st->stack->stack_data[st->start+2].u.num );
+ }
+ }else{
+ printf("script: getelementofarray (operator[]): param1 not name !\n");
+ push_val(st->stack,C_INT,0);
+ }
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_setlook(struct script_state *st)
+{
+ int type,val;
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ val=conv_num(st,& (st->stack->stack_data[st->start+3]));
+
+ pc_changelook(script_rid2sd(st),type,val);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_cutin(struct script_state *st)
+{
+ int type;
+
+ conv_str(st,& (st->stack->stack_data[st->start+2]));
+ type=conv_num(st,& (st->stack->stack_data[st->start+3]));
+
+ clif_cutin(script_rid2sd(st),st->stack->stack_data[st->start+2].u.str,type);
+
+ return 0;
+}
+/*==========================================
+ * カードのイラストを表示する
+ *------------------------------------------
+ */
+int buildin_cutincard(struct script_state *st)
+{
+ int itemid;
+
+ itemid=conv_num(st,& (st->stack->stack_data[st->start+2]));
+
+ clif_cutin(script_rid2sd(st),itemdb_search(itemid)->cardillustname,4);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_viewpoint(struct script_state *st)
+{
+ int type,x,y,id,color;
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ x=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ y=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ id=conv_num(st,& (st->stack->stack_data[st->start+5]));
+ color=conv_num(st,& (st->stack->stack_data[st->start+6]));
+
+ clif_viewpoint(script_rid2sd(st),st->oid,type,x,y,id,color);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_countitem(struct script_state *st)
+{
+ int nameid=0,count=0,i;
+ struct map_session_data *sd;
+
+ struct script_data *data;
+
+ sd = script_rid2sd(st);
+
+ data=&(st->stack->stack_data[st->start+2]);
+ get_val(st,data);
+ if( data->type==C_STR || data->type==C_CONSTSTR ){
+ const char *name=conv_str(st,data);
+ struct item_data *item_data;
+ if( (item_data = itemdb_searchname(name)) != NULL)
+ nameid=item_data->nameid;
+ }else
+ nameid=conv_num(st,data);
+
+ if (nameid>=500) //if no such ID then skip this iteration
+ for(i=0;i<MAX_INVENTORY;i++){
+ if(sd->status.inventory[i].nameid==nameid)
+ count+=sd->status.inventory[i].amount;
+ }
+ else{
+ if(battle_config.error_log)
+ printf("wrong item ID : countitem(%i)\n",nameid);
+ }
+ push_val(st->stack,C_INT,count);
+
+ return 0;
+}
+
+/*==========================================
+ * 重量チェック
+ *------------------------------------------
+ */
+int buildin_checkweight(struct script_state *st)
+{
+ int nameid=0,amount;
+ struct map_session_data *sd;
+ struct script_data *data;
+
+ sd = script_rid2sd(st);
+
+ data=&(st->stack->stack_data[st->start+2]);
+ get_val(st,data);
+ if( data->type==C_STR || data->type==C_CONSTSTR ){
+ const char *name=conv_str(st,data);
+ struct item_data *item_data = itemdb_searchname(name);
+ if( item_data )
+ nameid=item_data->nameid;
+ }else
+ nameid=conv_num(st,data);
+
+ amount=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ if ( amount<=0 || nameid<500 ) { //if get wrong item ID or amount<=0, don't count weight of non existing items
+ push_val(st->stack,C_INT,0);
+ }
+
+ sd=script_rid2sd(st);
+ if(itemdb_weight(nameid)*amount + sd->weight > sd->max_weight){
+ push_val(st->stack,C_INT,0);
+ } else {
+ push_val(st->stack,C_INT,1);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_getitem(struct script_state *st)
+{
+ int nameid,amount,flag = 0;
+ struct item item_tmp;
+ struct map_session_data *sd;
+ struct script_data *data;
+
+ sd = script_rid2sd(st);
+
+ data=&(st->stack->stack_data[st->start+2]);
+ get_val(st,data);
+ if( data->type==C_STR || data->type==C_CONSTSTR ){
+ const char *name=conv_str(st,data);
+ struct item_data *item_data = itemdb_searchname(name);
+ nameid=512; //Apple item ID
+ if( item_data != NULL)
+ nameid=item_data->nameid;
+ }else
+ nameid=conv_num(st,data);
+
+ if ( ( amount=conv_num(st,& (st->stack->stack_data[st->start+3])) ) <= 0) {
+ return 0; //return if amount <=0, skip the useles iteration
+ }
+ //Violet Box, Blue Box, etc - random item pick
+ if(nameid<0) { // ランダム
+ nameid=itemdb_searchrandomid(-nameid);
+ #ifndef TXT_ONLY
+ if(log_config.present > 0)
+ log_present(sd, -nameid, nameid);
+ #endif //USE_SQL
+ flag = 1;
+ }
+
+ if(nameid > 0) {
+ memset(&item_tmp,0,sizeof(item_tmp));
+ item_tmp.nameid=nameid;
+ if(!flag)
+ item_tmp.identify=1;
+ else
+ item_tmp.identify=!itemdb_isequip3(nameid);
+ if( st->end>st->start+5 ) //アイテムを指定したIDに渡す
+ sd=map_id2sd(conv_num(st,& (st->stack->stack_data[st->start+5])));
+ if(sd == NULL) //アイテムを渡す相手がいなかったらお帰り
+ return 0;
+ if((flag = pc_additem(sd,&item_tmp,amount))) {
+ clif_additem(sd,0,0,flag);
+ map_addflooritem(&item_tmp,amount,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_getitem2(struct script_state *st)
+{
+ int nameid,amount,flag = 0;
+ int iden,ref,attr,c1,c2,c3,c4;
+ struct item_data *item_data;
+ struct item item_tmp;
+ struct map_session_data *sd;
+ struct script_data *data;
+
+ sd = script_rid2sd(st);
+
+ data=&(st->stack->stack_data[st->start+2]);
+ get_val(st,data);
+ if( data->type==C_STR || data->type==C_CONSTSTR ){
+ const char *name=conv_str(st,data);
+ struct item_data *item_data = itemdb_searchname(name);
+ nameid=512; //Apple item ID
+ if( item_data )
+ nameid=item_data->nameid;
+ }else
+ nameid=conv_num(st,data);
+
+ amount=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ iden=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ ref=conv_num(st,& (st->stack->stack_data[st->start+5]));
+ attr=conv_num(st,& (st->stack->stack_data[st->start+6]));
+ c1=conv_num(st,& (st->stack->stack_data[st->start+7]));
+ c2=conv_num(st,& (st->stack->stack_data[st->start+8]));
+ c3=conv_num(st,& (st->stack->stack_data[st->start+9]));
+ c4=conv_num(st,& (st->stack->stack_data[st->start+10]));
+ if( st->end>st->start+11 ) //アイテムを指定したIDに渡す
+ sd=map_id2sd(conv_num(st,& (st->stack->stack_data[st->start+11])));
+ if(sd == NULL) //アイテムを渡す相手がいなかったらお帰り
+ return 0;
+
+ if(nameid<0) { // ランダム
+ nameid=itemdb_searchrandomid(-nameid);
+ flag = 1;
+ }
+
+ if(nameid > 0) {
+ memset(&item_tmp,0,sizeof(item_tmp));
+ item_data=itemdb_search(nameid);
+ if(item_data->type==4 || item_data->type==5){
+ if(ref > 10) ref = 10;
+ }
+ else if(item_data->type==7) {
+ iden = 1;
+ ref = 0;
+ }
+ else {
+ iden = 1;
+ ref = attr = 0;
+ }
+
+ item_tmp.nameid=nameid;
+ if(!flag)
+ item_tmp.identify=iden;
+ else if(item_data->type==4 || item_data->type==5)
+ item_tmp.identify=0;
+ item_tmp.refine=ref;
+ item_tmp.attribute=attr;
+ item_tmp.card[0]=c1;
+ item_tmp.card[1]=c2;
+ item_tmp.card[2]=c3;
+ item_tmp.card[3]=c4;
+ if((flag = pc_additem(sd,&item_tmp,amount))) {
+ clif_additem(sd,0,0,flag);
+ map_addflooritem(&item_tmp,amount,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
+ }
+ }
+
+ return 0;
+}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_makeitem(struct script_state *st)
+{
+ int nameid,amount,flag = 0;
+ int x,y,m;
+ char *mapname;
+ struct item item_tmp;
+ struct map_session_data *sd;
+ struct script_data *data;
+
+ sd = script_rid2sd(st);
+
+ data=&(st->stack->stack_data[st->start+2]);
+ get_val(st,data);
+ if( data->type==C_STR || data->type==C_CONSTSTR ){
+ const char *name=conv_str(st,data);
+ struct item_data *item_data = itemdb_searchname(name);
+ nameid=512; //Apple Item ID
+ if( item_data )
+ nameid=item_data->nameid;
+ }else
+ nameid=conv_num(st,data);
+
+ amount=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ mapname =conv_str(st,& (st->stack->stack_data[st->start+4]));
+ x =conv_num(st,& (st->stack->stack_data[st->start+5]));
+ y =conv_num(st,& (st->stack->stack_data[st->start+6]));
+
+ if( sd && strcmp(mapname,"this")==0)
+ m=sd->bl.m;
+ else
+ m=map_mapname2mapid(mapname);
+
+ if(nameid<0) { // ランダム
+ nameid=itemdb_searchrandomid(-nameid);
+ flag = 1;
+ }
+
+ if(nameid > 0) {
+ memset(&item_tmp,0,sizeof(item_tmp));
+ item_tmp.nameid=nameid;
+ if(!flag)
+ item_tmp.identify=1;
+ else
+ item_tmp.identify=!itemdb_isequip3(nameid);
+
+// clif_additem(sd,0,0,flag);
+ map_addflooritem(&item_tmp,amount,m,x,y,NULL,NULL,NULL,0);
+ }
+
+ return 0;
+}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_delitem(struct script_state *st)
+{
+ int nameid=0,amount,i;
+ struct map_session_data *sd;
+ struct script_data *data;
+
+ sd = script_rid2sd(st);
+
+ data=&(st->stack->stack_data[st->start+2]);
+ get_val(st,data);
+ if( data->type==C_STR || data->type==C_CONSTSTR ){
+ const char *name=conv_str(st,data);
+ struct item_data *item_data = itemdb_searchname(name);
+ //nameid=512;
+ if( item_data )
+ nameid=item_data->nameid;
+ }else
+ nameid=conv_num(st,data);
+
+ amount=conv_num(st,& (st->stack->stack_data[st->start+3]));
+
+ if (nameid<500 || amount<=0 ) {//by Lupus. Don't run FOR if u got wrong item ID or amount<=0
+ //printf("wrong item ID or amount<=0 : delitem %i,\n",nameid,amount);
+ return 0;
+ }
+ sd=script_rid2sd(st);
+
+ for(i=0;i<MAX_INVENTORY;i++){
+ if(sd->status.inventory[i].nameid<=0 || sd->inventory_data[i] == NULL ||
+ sd->inventory_data[i]->type!=7 ||
+ sd->status.inventory[i].amount<=0)
+ continue;
+ if(sd->status.inventory[i].nameid == nameid){
+ if(sd->status.inventory[i].card[0] == (short)0xff00){
+ if(search_petDB_index(nameid, PET_EGG) >= 0){
+ intif_delete_petdata(*((long *)(&sd->status.inventory[i].card[1])));
+ break;
+ }
+ }
+ }
+ }
+ for(i=0;i<MAX_INVENTORY;i++){
+ if(sd->status.inventory[i].nameid==nameid){
+ if(sd->status.inventory[i].amount>=amount){
+ pc_delitem(sd,i,amount,0);
+ break;
+ } else {
+ amount-=sd->status.inventory[i].amount;
+ if(amount==0)
+ amount=sd->status.inventory[i].amount;
+ pc_delitem(sd,i,amount,0);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *キャラ関係のパラメータ取得
+ *------------------------------------------
+ */
+int buildin_readparam(struct script_state *st)
+{
+ int type;
+ struct map_session_data *sd;
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ if( st->end>st->start+3 )
+ sd=map_nick2sd(conv_str(st,& (st->stack->stack_data[st->start+3])));
+ else
+ sd=script_rid2sd(st);
+
+ if(sd==NULL){
+ push_val(st->stack,C_INT,-1);
+ return 0;
+ }
+
+ push_val(st->stack,C_INT,pc_readparam(sd,type));
+
+ return 0;
+}
+/*==========================================
+ *キャラ関係のID取得
+ *------------------------------------------
+ */
+int buildin_getcharid(struct script_state *st)
+{
+ int num;
+ struct map_session_data *sd;
+
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ if( st->end>st->start+3 )
+ sd=map_nick2sd(conv_str(st,& (st->stack->stack_data[st->start+3])));
+ else
+ sd=script_rid2sd(st);
+ if(sd==NULL){
+ push_val(st->stack,C_INT,-1);
+ return 0;
+ }
+ if(num==0)
+ push_val(st->stack,C_INT,sd->status.char_id);
+ if(num==1)
+ push_val(st->stack,C_INT,sd->status.party_id);
+ if(num==2)
+ push_val(st->stack,C_INT,sd->status.guild_id);
+ if(num==3)
+ push_val(st->stack,C_INT,sd->status.account_id);
+ return 0;
+}
+/*==========================================
+ *指定IDのPT名取得
+ *------------------------------------------
+ */
+char *buildin_getpartyname_sub(int party_id)
+{
+ struct party *p;
+
+ p=NULL;
+ p=party_search(party_id);
+
+ if(p!=NULL){
+ char *buf;
+ buf=(char *)aCalloc(24,sizeof(char));
+ strcpy(buf,p->name);
+ return buf;
+ }
+
+ return 0;
+}
+int buildin_getpartyname(struct script_state *st)
+{
+ char *name;
+ int party_id;
+
+ party_id=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ name=buildin_getpartyname_sub(party_id);
+ if(name!=0)
+ push_str(st->stack,C_STR,name);
+ else
+ push_str(st->stack,C_CONSTSTR,"null");
+
+ return 0;
+}
+/*==========================================
+ *指定IDのPT人数とメンバーID取得
+ *------------------------------------------
+ */
+int buildin_getpartymember(struct script_state *st)
+{
+ struct party *p;
+ int i,j=0;
+
+ p=NULL;
+ p=party_search(conv_num(st,& (st->stack->stack_data[st->start+2])));
+
+ if(p!=NULL){
+ for(i=0;i<MAX_PARTY;i++){
+ if(p->member[i].account_id){
+// printf("name:%s %d\n",p->member[i].name,i);
+ mapreg_setregstr(add_str("$@partymembername$")+(i<<24),p->member[i].name);
+ j++;
+ }
+ }
+ }
+ mapreg_setreg(add_str("$@partymembercount"),j);
+
+ return 0;
+}
+/*==========================================
+ *指定IDのギルド名取得
+ *------------------------------------------
+ */
+char *buildin_getguildname_sub(int guild_id)
+{
+ struct guild *g=NULL;
+ g=guild_search(guild_id);
+
+ if(g!=NULL){
+ char *buf;
+ buf=(char *)aCalloc(24,sizeof(char));
+ strcpy(buf,g->name);
+ return buf;
+ }
+ return 0;
+}
+int buildin_getguildname(struct script_state *st)
+{
+ char *name;
+ int guild_id=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ name=buildin_getguildname_sub(guild_id);
+ if(name!=0)
+ push_str(st->stack,C_STR,name);
+ else
+ push_str(st->stack,C_CONSTSTR,"null");
+ return 0;
+}
+
+/*==========================================
+ *指定IDのGuildMaster名取得
+ *------------------------------------------
+ */
+char *buildin_getguildmaster_sub(int guild_id)
+{
+ struct guild *g=NULL;
+ g=guild_search(guild_id);
+
+ if(g!=NULL){
+ char *buf;
+ buf=(char *)aCalloc(24,sizeof(char));
+ strncpy(buf,g->master, 23);
+ return buf;
+ }
+
+ return 0;
+}
+int buildin_getguildmaster(struct script_state *st)
+{
+ char *master;
+ int guild_id=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ master=buildin_getguildmaster_sub(guild_id);
+ if(master!=0)
+ push_str(st->stack,C_STR,master);
+ else
+ push_str(st->stack,C_CONSTSTR,"null");
+ return 0;
+}
+
+int buildin_getguildmasterid(struct script_state *st)
+{
+ char *master;
+ struct map_session_data *sd=NULL;
+ int guild_id=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ master=buildin_getguildmaster_sub(guild_id);
+ if(master!=0){
+ if((sd=map_nick2sd(master)) == NULL){
+ push_val(st->stack,C_INT,0);
+ return 0;
+ }
+ push_val(st->stack,C_INT,sd->status.char_id);
+ }else{
+ push_val(st->stack,C_INT,0);
+ }
+ return 0;
+}
+
+/*==========================================
+ * キャラクタの名前
+ *------------------------------------------
+ */
+int buildin_strcharinfo(struct script_state *st)
+{
+ struct map_session_data *sd;
+ int num;
+
+ sd=script_rid2sd(st);
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ if(num==0){
+ char *buf;
+ buf=(char *)aCalloc(24,sizeof(char));
+ strncpy(buf,sd->status.name, 23);
+ push_str(st->stack,C_STR,buf);
+ }
+ if(num==1){
+ char *buf;
+ buf=buildin_getpartyname_sub(sd->status.party_id);
+ if(buf!=0)
+ push_str(st->stack,C_STR,buf);
+ else
+ push_str(st->stack,C_CONSTSTR,"");
+ }
+ if(num==2){
+ char *buf;
+ buf=buildin_getguildname_sub(sd->status.guild_id);
+ if(buf!=0)
+ push_str(st->stack,C_STR,buf);
+ else
+ push_str(st->stack,C_CONSTSTR,"");
+ }
+
+ return 0;
+}
+
+unsigned int equip[10]={0x0100,0x0010,0x0020,0x0002,0x0004,0x0040,0x0008,0x0080,0x0200,0x0001};
+
+/*==========================================
+ * GetEquipID(Pos); Pos: 1-10
+ *------------------------------------------
+ */
+int buildin_getequipid(struct script_state *st)
+{
+ int i,num;
+ struct map_session_data *sd;
+ struct item_data* item;
+
+ sd=script_rid2sd(st);
+ if(sd == NULL)
+ {
+ printf("getequipid: sd == NULL\n");
+ return 0;
+ }
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ i=pc_checkequip(sd,equip[num-1]);
+ if(i >= 0){
+ item=sd->inventory_data[i];
+ if(item)
+ push_val(st->stack,C_INT,item->nameid);
+ else
+ push_val(st->stack,C_INT,0);
+ }else{
+ push_val(st->stack,C_INT,-1);
+ }
+ return 0;
+}
+
+/*==========================================
+ * 装備名文字列(精錬メニュー用)
+ *------------------------------------------
+ */
+int buildin_getequipname(struct script_state *st)
+{
+ int i,num;
+ struct map_session_data *sd;
+ struct item_data* item;
+ char *buf;
+
+ buf=(char *)aCalloc(64,sizeof(char));
+ sd=script_rid2sd(st);
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ i=pc_checkequip(sd,equip[num-1]);
+ if(i >= 0){
+ item=sd->inventory_data[i];
+ if(item)
+ sprintf(buf,"%s-[%s]",pos[num-1],item->jname);
+ else
+ sprintf(buf,"%s-[%s]",pos[num-1],pos[10]);
+ }else{
+ sprintf(buf,"%s-[%s]",pos[num-1],pos[10]);
+ }
+ push_str(st->stack,C_STR,buf);
+
+ return 0;
+}
+
+/*==========================================
+ * getbrokenid [Valaris]
+ *------------------------------------------
+ */
+int buildin_getbrokenid(struct script_state *st)
+{
+ int i,num,id=0,brokencounter=0;
+ struct map_session_data *sd;
+
+ sd=script_rid2sd(st);
+
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ for(i=0; i<MAX_INVENTORY; i++) {
+ if(sd->status.inventory[i].attribute==1){
+ brokencounter++;
+ if(num==brokencounter){
+ id=sd->status.inventory[i].nameid;
+ break;
+ }
+ }
+ }
+
+ push_val(st->stack,C_INT,id);
+
+ return 0;
+}
+
+/*==========================================
+ * repair [Valaris]
+ *------------------------------------------
+ */
+int buildin_repair(struct script_state *st)
+{
+ int i,num;
+ int repaircounter=0;
+ struct map_session_data *sd;
+
+
+ sd=script_rid2sd(st);
+
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ for(i=0; i<MAX_INVENTORY; i++) {
+ if(sd->status.inventory[i].attribute==1){
+ repaircounter++;
+ if(num==repaircounter){
+ sd->status.inventory[i].attribute=0;
+ clif_equiplist(sd);
+ clif_produceeffect(sd, 0, sd->status.inventory[i].nameid);
+ clif_misceffect(&sd->bl, 3);
+ clif_displaymessage(sd->fd,"Item has been repaired.");
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 装備チェック
+ *------------------------------------------
+ */
+int buildin_getequipisequiped(struct script_state *st)
+{
+ int i,num;
+ struct map_session_data *sd;
+
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sd=script_rid2sd(st);
+ i=pc_checkequip(sd,equip[num-1]);
+ if(i >= 0){
+ push_val(st->stack,C_INT,1);
+ }else{
+ push_val(st->stack,C_INT,0);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 装備品精錬可能チェック
+ *------------------------------------------
+ */
+int buildin_getequipisenableref(struct script_state *st)
+{
+ int i,num;
+ struct map_session_data *sd;
+
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sd=script_rid2sd(st);
+ i=pc_checkequip(sd,equip[num-1]);
+ if(i >= 0 && num<7 && sd->inventory_data[i] && (num!=1 || sd->inventory_data[i]->def > 1
+ || (sd->inventory_data[i]->def==1 && sd->inventory_data[i]->equip_script==NULL)
+ || (sd->inventory_data[i]->def<=0 && sd->inventory_data[i]->equip_script!=NULL))
+ ){
+ push_val(st->stack,C_INT,1);
+ }else{
+ push_val(st->stack,C_INT,0);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 装備品鑑定チェック
+ *------------------------------------------
+ */
+int buildin_getequipisidentify(struct script_state *st)
+{
+ int i,num;
+ struct map_session_data *sd;
+
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sd=script_rid2sd(st);
+ i=pc_checkequip(sd,equip[num-1]);
+ if(i >= 0)
+ push_val(st->stack,C_INT,sd->status.inventory[i].identify);
+ else
+ push_val(st->stack,C_INT,0);
+
+ return 0;
+}
+
+/*==========================================
+ * 装備品精錬度
+ *------------------------------------------
+ */
+int buildin_getequiprefinerycnt(struct script_state *st)
+{
+ int i,num;
+ struct map_session_data *sd;
+
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sd=script_rid2sd(st);
+ i=pc_checkequip(sd,equip[num-1]);
+ if(i >= 0)
+ push_val(st->stack,C_INT,sd->status.inventory[i].refine);
+ else
+ push_val(st->stack,C_INT,0);
+
+ return 0;
+}
+
+/*==========================================
+ * 装備品武器LV
+ *------------------------------------------
+ */
+int buildin_getequipweaponlv(struct script_state *st)
+{
+ int i,num;
+ struct map_session_data *sd;
+
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sd=script_rid2sd(st);
+ i=pc_checkequip(sd,equip[num-1]);
+ if(i >= 0 && sd->inventory_data[i])
+ push_val(st->stack,C_INT,sd->inventory_data[i]->wlv);
+ else
+ push_val(st->stack,C_INT,0);
+
+ return 0;
+}
+
+/*==========================================
+ * 装備品精錬成功率
+ *------------------------------------------
+ */
+int buildin_getequippercentrefinery(struct script_state *st)
+{
+ int i,num;
+ struct map_session_data *sd;
+
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sd=script_rid2sd(st);
+ i=pc_checkequip(sd,equip[num-1]);
+ if(i >= 0)
+ push_val(st->stack,C_INT,pc_percentrefinery(sd,&sd->status.inventory[i]));
+ else
+ push_val(st->stack,C_INT,0);
+
+ return 0;
+}
+
+/*==========================================
+ * 精錬成功
+ *------------------------------------------
+ */
+int buildin_successrefitem(struct script_state *st)
+{
+ int i,num,ep;
+ struct map_session_data *sd;
+
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sd=script_rid2sd(st);
+ i=pc_checkequip(sd,equip[num-1]);
+ if(i >= 0) {
+ ep=sd->status.inventory[i].equip;
+
+ #ifndef TXT_ONLY
+ if(log_config.refine > 0)
+ log_refine(sd, i, 1);
+ #endif //USE_SQL
+
+ sd->status.inventory[i].refine++;
+ pc_unequipitem(sd,i,0);
+ clif_refine(sd->fd,sd,0,i,sd->status.inventory[i].refine);
+ clif_delitem(sd,i,1);
+ clif_additem(sd,i,1,0);
+ pc_equipitem(sd,i,ep);
+ clif_misceffect(&sd->bl,3);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * 精錬失敗
+ *------------------------------------------
+ */
+int buildin_failedrefitem(struct script_state *st)
+{
+ int i,num;
+ struct map_session_data *sd;
+
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sd=script_rid2sd(st);
+ i=pc_checkequip(sd,equip[num-1]);
+ if(i >= 0) {
+ #ifndef TXT_ONLY
+ if(log_config.refine > 0)
+ log_refine(sd, i, 0);
+ #endif //USE_SQL
+
+ sd->status.inventory[i].refine = 0;
+ pc_unequipitem(sd,i,0);
+ // 精錬失敗エフェクトのパケット
+ clif_refine(sd->fd,sd,1,i,sd->status.inventory[i].refine);
+ pc_delitem(sd,i,1,0);
+ // 他の人にも失敗を通知
+ clif_misceffect(&sd->bl,2);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_statusup(struct script_state *st)
+{
+ int type;
+ struct map_session_data *sd;
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sd=script_rid2sd(st);
+ pc_statusup(sd,type);
+
+ return 0;
+}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_statusup2(struct script_state *st)
+{
+ int type,val;
+ struct map_session_data *sd;
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ val=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ sd=script_rid2sd(st);
+ pc_statusup2(sd,type,val);
+
+ return 0;
+}
+/*==========================================
+ * 装備品による能力値ボーナス
+ *------------------------------------------
+ */
+int buildin_bonus(struct script_state *st)
+{
+ int type,val;
+ struct map_session_data *sd;
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ val=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ sd=script_rid2sd(st);
+ pc_bonus(sd,type,val);
+
+ return 0;
+}
+/*==========================================
+ * 装備品による能力値ボーナス
+ *------------------------------------------
+ */
+int buildin_bonus2(struct script_state *st)
+{
+ int type,type2,val;
+ struct map_session_data *sd;
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ type2=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ val=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ sd=script_rid2sd(st);
+ pc_bonus2(sd,type,type2,val);
+
+ return 0;
+}
+/*==========================================
+ * 装備品による能力値ボーナス
+ *------------------------------------------
+ */
+int buildin_bonus3(struct script_state *st)
+{
+ int type,type2,type3,val;
+ struct map_session_data *sd;
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ type2=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ type3=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ val=conv_num(st,& (st->stack->stack_data[st->start+5]));
+ sd=script_rid2sd(st);
+ pc_bonus3(sd,type,type2,type3,val);
+
+ return 0;
+}
+/*==========================================
+ * スキル所得
+ *------------------------------------------
+ */
+int buildin_skill(struct script_state *st)
+{
+ int id,level,flag=1;
+ struct map_session_data *sd;
+
+ id=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ level=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ if( st->end>st->start+4 )
+ flag=conv_num(st,&(st->stack->stack_data[st->start+4]) );
+ sd=script_rid2sd(st);
+ pc_skill(sd,id,level,flag);
+
+ return 0;
+}
+/*==========================================
+ * ギルドスキル取得
+ *------------------------------------------
+ */
+int buildin_guildskill(struct script_state *st)
+{
+ int id,level,flag=0;
+ struct map_session_data *sd;
+ int i=0;
+
+ id=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ level=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ if( st->end>st->start+4 )
+ flag=conv_num(st,&(st->stack->stack_data[st->start+4]) );
+ sd=script_rid2sd(st);
+ for(i=0;i<level;i++)
+ guild_skillup(sd,id,flag);
+
+ return 0;
+}
+/*==========================================
+ * スキルレベル所得
+ *------------------------------------------
+ */
+int buildin_getskilllv(struct script_state *st)
+{
+ int id=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ push_val(st->stack,C_INT, pc_checkskill( script_rid2sd(st) ,id) );
+ return 0;
+}
+/*==========================================
+ * getgdskilllv(Guild_ID, Skill_ID);
+ * skill_id = 10000 : GD_APPROVAL
+ * 10001 : GD_KAFRACONTACT
+ * 10002 : GD_GUARDIANRESEARCH
+ * 10003 : GD_CHARISMA
+ * 10004 : GD_EXTENSION
+ *------------------------------------------
+ */
+int buildin_getgdskilllv(struct script_state *st)
+{
+ int guild_id=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ int skill_id=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ struct guild *g=guild_search(guild_id);
+ push_val(st->stack,C_INT, (g==NULL)?-1:guild_checkskill(g,skill_id) );
+ return 0;
+/*
+ struct map_session_data *sd=NULL;
+ struct guild *g=NULL;
+ int skill_id;
+
+ skill_id=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sd=script_rid2sd(st);
+ if(sd && sd->status.guild_id > 0) g=guild_search(sd->status.guild_id);
+ if(sd && g) {
+ push_val(st->stack,C_INT, guild_checkskill(g,skill_id+9999) );
+ } else {
+ push_val(st->stack,C_INT,-1);
+ }
+ return 0;
+*/
+}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_basicskillcheck(struct script_state *st)
+{
+ push_val(st->stack,C_INT, battle_config.basic_skill_check);
+ return 0;
+}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_getgmlevel(struct script_state *st)
+{
+ push_val(st->stack,C_INT, pc_isGM(script_rid2sd(st)));
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_end(struct script_state *st)
+{
+ st->state = END;
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_checkoption(struct script_state *st)
+{
+ int type;
+ struct map_session_data *sd;
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sd=script_rid2sd(st);
+
+ if(sd->status.option & type){
+ push_val(st->stack,C_INT,1);
+ } else {
+ push_val(st->stack,C_INT,0);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_setoption(struct script_state *st)
+{
+ int type;
+ struct map_session_data *sd;
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sd=script_rid2sd(st);
+ pc_setoption(sd,type);
+
+ return 0;
+}
+
+/*==========================================
+ * Checkcart [Valaris]
+ *------------------------------------------
+ */
+
+int buildin_checkcart(struct script_state *st)
+{
+ struct map_session_data *sd;
+
+ sd=script_rid2sd(st);
+
+ if(pc_iscarton(sd)){
+ push_val(st->stack,C_INT,1);
+ } else {
+ push_val(st->stack,C_INT,0);
+ }
+ return 0;
+}
+
+/*==========================================
+ * カートを付ける
+ *------------------------------------------
+ */
+int buildin_setcart(struct script_state *st)
+{
+ struct map_session_data *sd;
+
+ sd=script_rid2sd(st);
+ pc_setcart(sd,1);
+
+ return 0;
+}
+
+/*==========================================
+ * checkfalcon [Valaris]
+ *------------------------------------------
+ */
+
+int buildin_checkfalcon(struct script_state *st)
+{
+ struct map_session_data *sd;
+
+ sd=script_rid2sd(st);
+
+ if(pc_isfalcon(sd)){
+ push_val(st->stack,C_INT,1);
+ } else {
+ push_val(st->stack,C_INT,0);
+ }
+
+ return 0;
+}
+
+
+/*==========================================
+ * 鷹を付ける
+ *------------------------------------------
+ */
+int buildin_setfalcon(struct script_state *st)
+{
+ struct map_session_data *sd;
+
+ sd=script_rid2sd(st);
+ pc_setfalcon(sd);
+
+ return 0;
+}
+
+/*==========================================
+ * Checkcart [Valaris]
+ *------------------------------------------
+ */
+
+int buildin_checkriding(struct script_state *st)
+{
+ struct map_session_data *sd;
+
+ sd=script_rid2sd(st);
+
+ if(pc_isriding(sd)){
+ push_val(st->stack,C_INT,1);
+ } else {
+ push_val(st->stack,C_INT,0);
+ }
+
+ return 0;
+}
+
+
+/*==========================================
+ * ペコペコ乗り
+ *------------------------------------------
+ */
+int buildin_setriding(struct script_state *st)
+{
+ struct map_session_data *sd;
+
+ sd=script_rid2sd(st);
+ pc_setriding(sd);
+
+ return 0;
+}
+
+/*==========================================
+ * セーブポイントの保存
+ *------------------------------------------
+ */
+int buildin_savepoint(struct script_state *st)
+{
+ int x,y;
+ char *str;
+
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ x=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ y=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ pc_setsavepoint(script_rid2sd(st),str,x,y);
+ return 0;
+}
+
+/*==========================================
+ * GetTimeTick(0: System Tick, 1: Time Second Tick)
+ *------------------------------------------
+ */
+int buildin_gettimetick(struct script_state *st) /* Asgard Version */
+{
+ int type;
+ time_t timer;
+ struct tm *t;
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+
+ switch(type){
+ case 1:
+ //type 1:(Second Ticks: 0-86399, 00:00:00-23:59:59)
+ time(&timer);
+ t=localtime(&timer);
+ push_val(st->stack,C_INT,((t->tm_hour)*3600+(t->tm_min)*60+t->tm_sec));
+ break;
+ case 0:
+ default:
+ //type 0:(System Ticks)
+ push_val(st->stack,C_INT,gettick());
+ break;
+ }
+ return 0;
+}
+
+/*==========================================
+ * GetTime(Type);
+ * 1: Sec 2: Min 3: Hour
+ * 4: WeekDay 5: MonthDay 6: Month
+ * 7: Year
+ *------------------------------------------
+ */
+int buildin_gettime(struct script_state *st) /* Asgard Version */
+{
+ int type;
+ time_t timer;
+ struct tm *t;
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+
+ time(&timer);
+ t=localtime(&timer);
+
+ switch(type){
+ case 1://Sec(0~59)
+ push_val(st->stack,C_INT,t->tm_sec);
+ break;
+ case 2://Min(0~59)
+ push_val(st->stack,C_INT,t->tm_min);
+ break;
+ case 3://Hour(0~23)
+ push_val(st->stack,C_INT,t->tm_hour);
+ break;
+ case 4://WeekDay(0~6)
+ push_val(st->stack,C_INT,t->tm_wday);
+ break;
+ case 5://MonthDay(01~31)
+ push_val(st->stack,C_INT,t->tm_mday);
+ break;
+ case 6://Month(01~12)
+ push_val(st->stack,C_INT,t->tm_mon+1);
+ break;
+ case 7://Year(20xx)
+ push_val(st->stack,C_INT,t->tm_year+1900);
+ break;
+ default://(format error)
+ push_val(st->stack,C_INT,-1);
+ break;
+ }
+ return 0;
+}
+
+/*==========================================
+ * GetTimeStr("TimeFMT", Length);
+ *------------------------------------------
+ */
+int buildin_gettimestr(struct script_state *st)
+{
+ char *tmpstr;
+ char *fmtstr;
+ int maxlen;
+ time_t now = time(NULL);
+
+ fmtstr=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ maxlen=conv_num(st,& (st->stack->stack_data[st->start+3]));
+
+ tmpstr=(char *)aCalloc(maxlen+1,sizeof(char));
+ strftime(tmpstr,maxlen,fmtstr,localtime(&now));
+ tmpstr[maxlen]='\0';
+
+ push_str(st->stack,C_STR,tmpstr);
+ return 0;
+}
+
+/*==========================================
+ * カプラ倉庫を開く
+ *------------------------------------------
+ */
+int buildin_openstorage(struct script_state *st)
+{
+ storage_storageopen(script_rid2sd(st));
+ return 0;
+}
+
+int buildin_guildopenstorage(struct script_state *st)
+{
+ struct map_session_data *sd=script_rid2sd(st);
+ int ret;
+ ret = storage_guild_storageopen(sd);
+ push_val(st->stack,C_INT,ret);
+ return 0;
+}
+
+/*==========================================
+ * アイテムによるスキル発動
+ *------------------------------------------
+ */
+int buildin_itemskill(struct script_state *st)
+{
+ int id,lv;
+ char *str;
+ struct map_session_data *sd=script_rid2sd(st);
+
+ id=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ lv=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ str=conv_str(st,& (st->stack->stack_data[st->start+4]));
+
+ // 詠唱中にスキルアイテムは使用できない
+ if(sd->skilltimer != -1)
+ return 0;
+
+ sd->skillitem=id;
+ sd->skillitemlv=lv;
+ clif_item_skill(sd,id,lv,str);
+ return 0;
+}
+/*==========================================
+ * アイテム作成
+ *------------------------------------------
+ */
+int buildin_produce(struct script_state *st)
+{
+ int trigger;
+ struct map_session_data *sd=script_rid2sd(st);
+
+ if( sd->state.produce_flag == 1) return 0;
+ trigger=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ clif_skill_produce_mix_list(sd,trigger);
+ return 0;
+}
+/*==========================================
+ * NPCでペット作る
+ *------------------------------------------
+ */
+int buildin_makepet(struct script_state *st)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ struct script_data *data;
+ int id,pet_id;
+
+ data=&(st->stack->stack_data[st->start+2]);
+ get_val(st,data);
+
+ id=conv_num(st,data);
+
+ pet_id = search_petDB_index(id, PET_CLASS);
+
+ if (pet_id < 0)
+ pet_id = search_petDB_index(id, PET_EGG);
+ if (pet_id >= 0 && sd) {
+ sd->catch_target_class = pet_db[pet_id].class;
+ intif_create_pet(
+ sd->status.account_id, sd->status.char_id,
+ pet_db[pet_id].class, mob_db[pet_db[pet_id].class].lv,
+ pet_db[pet_id].EggID, 0, pet_db[pet_id].intimate,
+ 100, 0, 1, pet_db[pet_id].jname);
+ }
+
+ return 0;
+}
+/*==========================================
+ * NPCで経験値上げる
+ *------------------------------------------
+ */
+int buildin_getexp(struct script_state *st)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ int base=0,job=0;
+
+ base=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ job =conv_num(st,& (st->stack->stack_data[st->start+3]));
+ if(base<0 || job<0)
+ return 0;
+ if(sd)
+ pc_gainexp(sd,base,job);
+
+ return 0;
+}
+
+/*==========================================
+ * モンスター発生
+ *------------------------------------------
+ */
+int buildin_monster(struct script_state *st)
+{
+ int class,amount,x,y;
+ char *str,*map,*event="";
+
+ map =conv_str(st,& (st->stack->stack_data[st->start+2]));
+ x =conv_num(st,& (st->stack->stack_data[st->start+3]));
+ y =conv_num(st,& (st->stack->stack_data[st->start+4]));
+ str =conv_str(st,& (st->stack->stack_data[st->start+5]));
+ class=conv_num(st,& (st->stack->stack_data[st->start+6]));
+ amount=conv_num(st,& (st->stack->stack_data[st->start+7]));
+ if( st->end>st->start+8 )
+ event=conv_str(st,& (st->stack->stack_data[st->start+8]));
+
+ mob_once_spawn(map_id2sd(st->rid),map,x,y,str,class,amount,event);
+ return 0;
+}
+/*==========================================
+ * モンスター発生
+ *------------------------------------------
+ */
+int buildin_areamonster(struct script_state *st)
+{
+ int class,amount,x0,y0,x1,y1;
+ char *str,*map,*event="";
+
+ map =conv_str(st,& (st->stack->stack_data[st->start+2]));
+ x0 =conv_num(st,& (st->stack->stack_data[st->start+3]));
+ y0 =conv_num(st,& (st->stack->stack_data[st->start+4]));
+ x1 =conv_num(st,& (st->stack->stack_data[st->start+5]));
+ y1 =conv_num(st,& (st->stack->stack_data[st->start+6]));
+ str =conv_str(st,& (st->stack->stack_data[st->start+7]));
+ class=conv_num(st,& (st->stack->stack_data[st->start+8]));
+ amount=conv_num(st,& (st->stack->stack_data[st->start+9]));
+ if( st->end>st->start+10 )
+ event=conv_str(st,& (st->stack->stack_data[st->start+10]));
+
+ mob_once_spawn_area(map_id2sd(st->rid),map,x0,y0,x1,y1,str,class,amount,event);
+ return 0;
+}
+/*==========================================
+ * モンスター削除
+ *------------------------------------------
+ */
+int buildin_killmonster_sub(struct block_list *bl,va_list ap)
+{
+ char *event=va_arg(ap,char *);
+ int allflag=va_arg(ap,int);
+
+ if(!allflag){
+ if(strcmp(event,((struct mob_data *)bl)->npc_event)==0)
+ mob_delete((struct mob_data *)bl);
+ return 0;
+ }else if(allflag){
+ if(((struct mob_data *)bl)->spawndelay1==-1 && ((struct mob_data *)bl)->spawndelay2==-1)
+ mob_delete((struct mob_data *)bl);
+ return 0;
+ }
+ return 0;
+}
+int buildin_killmonster(struct script_state *st)
+{
+ char *mapname,*event;
+ int m,allflag=0;
+ mapname=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ event=conv_str(st,& (st->stack->stack_data[st->start+3]));
+ if(strcmp(event,"All")==0)
+ allflag = 1;
+
+ if( (m=map_mapname2mapid(mapname))<0 )
+ return 0;
+ map_foreachinarea(buildin_killmonster_sub,
+ m,0,0,map[m].xs,map[m].ys,BL_MOB, event ,allflag);
+ return 0;
+}
+
+int buildin_killmonsterall_sub(struct block_list *bl,va_list ap)
+{
+ mob_delete((struct mob_data *)bl);
+ return 0;
+}
+int buildin_killmonsterall(struct script_state *st)
+{
+ char *mapname;
+ int m;
+ mapname=conv_str(st,& (st->stack->stack_data[st->start+2]));
+
+ if( (m=map_mapname2mapid(mapname))<0 )
+ return 0;
+ map_foreachinarea(buildin_killmonsterall_sub,
+ m,0,0,map[m].xs,map[m].ys,BL_MOB);
+ return 0;
+}
+
+/*==========================================
+ * イベント実行
+ *------------------------------------------
+ */
+int buildin_doevent(struct script_state *st)
+{
+ char *event;
+ event=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ npc_event(map_id2sd(st->rid),event,0);
+ return 0;
+}
+/*==========================================
+ * NPC主体イベント実行
+ *------------------------------------------
+ */
+int buildin_donpcevent(struct script_state *st)
+{
+ char *event;
+ event=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ npc_event_do(event);
+ return 0;
+}
+/*==========================================
+ * イベントタイマー追加
+ *------------------------------------------
+ */
+int buildin_addtimer(struct script_state *st)
+{
+ char *event;
+ int tick;
+ tick=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ event=conv_str(st,& (st->stack->stack_data[st->start+3]));
+ pc_addeventtimer(script_rid2sd(st),tick,event);
+ return 0;
+}
+/*==========================================
+ * イベントタイマー削除
+ *------------------------------------------
+ */
+int buildin_deltimer(struct script_state *st)
+{
+ char *event;
+ event=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ pc_deleventtimer(script_rid2sd(st),event);
+ return 0;
+}
+/*==========================================
+ * イベントタイマーのカウント値追加
+ *------------------------------------------
+ */
+int buildin_addtimercount(struct script_state *st)
+{
+ char *event;
+ int tick;
+ event=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ tick=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ pc_addeventtimercount(script_rid2sd(st),event,tick);
+ return 0;
+}
+
+/*==========================================
+ * NPCタイマー初期化
+ *------------------------------------------
+ */
+int buildin_initnpctimer(struct script_state *st)
+{
+ struct npc_data *nd;
+ if( st->end > st->start+2 )
+ nd=npc_name2id(conv_str(st,& (st->stack->stack_data[st->start+2])));
+ else
+ nd=(struct npc_data *)map_id2bl(st->oid);
+
+ npc_settimerevent_tick(nd,0);
+ npc_timerevent_start(nd);
+ return 0;
+}
+/*==========================================
+ * NPCタイマー開始
+ *------------------------------------------
+ */
+int buildin_startnpctimer(struct script_state *st)
+{
+ struct npc_data *nd;
+ if( st->end > st->start+2 )
+ nd=npc_name2id(conv_str(st,& (st->stack->stack_data[st->start+2])));
+ else
+ nd=(struct npc_data *)map_id2bl(st->oid);
+
+ npc_timerevent_start(nd);
+ return 0;
+}
+/*==========================================
+ * NPCタイマー停止
+ *------------------------------------------
+ */
+int buildin_stopnpctimer(struct script_state *st)
+{
+ struct npc_data *nd;
+ if( st->end > st->start+2 )
+ nd=npc_name2id(conv_str(st,& (st->stack->stack_data[st->start+2])));
+ else
+ nd=(struct npc_data *)map_id2bl(st->oid);
+
+ npc_timerevent_stop(nd);
+ return 0;
+}
+/*==========================================
+ * NPCタイマー情報所得
+ *------------------------------------------
+ */
+int buildin_getnpctimer(struct script_state *st)
+{
+ struct npc_data *nd;
+ int type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ int val=0;
+ if( st->end > st->start+3 )
+ nd=npc_name2id(conv_str(st,& (st->stack->stack_data[st->start+3])));
+ else
+ nd=(struct npc_data *)map_id2bl(st->oid);
+
+ switch(type){
+ case 0: val=npc_gettimerevent_tick(nd); break;
+ case 1: val= (nd->u.scr.nexttimer>=0); break;
+ case 2: val= nd->u.scr.timeramount; break;
+ }
+ push_val(st->stack,C_INT,val);
+ return 0;
+}
+/*==========================================
+ * NPCタイマー値設定
+ *------------------------------------------
+ */
+int buildin_setnpctimer(struct script_state *st)
+{
+ int tick;
+ struct npc_data *nd;
+ tick=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ if( st->end > st->start+3 )
+ nd=npc_name2id(conv_str(st,& (st->stack->stack_data[st->start+3])));
+ else
+ nd=(struct npc_data *)map_id2bl(st->oid);
+
+ npc_settimerevent_tick(nd,tick);
+ return 0;
+}
+
+/*==========================================
+ * 天の声アナウンス
+ *------------------------------------------
+ */
+int buildin_announce(struct script_state *st)
+{
+ char *str;
+ int flag;
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ flag=conv_num(st,& (st->stack->stack_data[st->start+3]));
+
+ if(flag&0x0f){
+ struct block_list *bl=(flag&0x08)? map_id2bl(st->oid) :
+ (struct block_list *)script_rid2sd(st);
+ clif_GMmessage(bl,str,strlen(str)+1,flag);
+ }else
+ intif_GMmessage(str,strlen(str)+1,flag);
+ return 0;
+}
+/*==========================================
+ * 天の声アナウンス(特定マップ)
+ *------------------------------------------
+ */
+int buildin_mapannounce_sub(struct block_list *bl,va_list ap)
+{
+ char *str;
+ int len,flag;
+ str=va_arg(ap,char *);
+ len=va_arg(ap,int);
+ flag=va_arg(ap,int);
+ clif_GMmessage(bl,str,len,flag|3);
+ return 0;
+}
+int buildin_mapannounce(struct script_state *st)
+{
+ char *mapname,*str;
+ int flag,m;
+
+ mapname=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ str=conv_str(st,& (st->stack->stack_data[st->start+3]));
+ flag=conv_num(st,& (st->stack->stack_data[st->start+4]));
+
+ if( (m=map_mapname2mapid(mapname))<0 )
+ return 0;
+ map_foreachinarea(buildin_mapannounce_sub,
+ m,0,0,map[m].xs,map[m].ys,BL_PC, str,strlen(str)+1,flag&0x10);
+ return 0;
+}
+/*==========================================
+ * 天の声アナウンス(特定エリア)
+ *------------------------------------------
+ */
+int buildin_areaannounce(struct script_state *st)
+{
+ char *map,*str;
+ int flag,m;
+ int x0,y0,x1,y1;
+
+ map=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ x0=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ y0=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ x1=conv_num(st,& (st->stack->stack_data[st->start+5]));
+ y1=conv_num(st,& (st->stack->stack_data[st->start+6]));
+ str=conv_str(st,& (st->stack->stack_data[st->start+7]));
+ flag=conv_num(st,& (st->stack->stack_data[st->start+8]));
+
+ if( (m=map_mapname2mapid(map))<0 )
+ return 0;
+
+ map_foreachinarea(buildin_mapannounce_sub,
+ m,x0,y0,x1,y1,BL_PC, str,strlen(str)+1,flag&0x10 );
+ return 0;
+}
+/*==========================================
+ * ユーザー数所得
+ *------------------------------------------
+ */
+int buildin_getusers(struct script_state *st)
+{
+ int flag=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ struct block_list *bl=map_id2bl((flag&0x08)?st->oid:st->rid);
+ int val=0;
+ switch(flag&0x07){
+ case 0: val=map[bl->m].users; break;
+ case 1: val=map_getusers(); break;
+ }
+ push_val(st->stack,C_INT,val);
+ return 0;
+}
+/*==========================================
+ * マップ指定ユーザー数所得
+ *------------------------------------------
+ */
+int buildin_getmapusers(struct script_state *st)
+{
+ char *str;
+ int m;
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ if( (m=map_mapname2mapid(str))< 0){
+ push_val(st->stack,C_INT,-1);
+ return 0;
+ }
+ push_val(st->stack,C_INT,map[m].users);
+ return 0;
+}
+/*==========================================
+ * エリア指定ユーザー数所得
+ *------------------------------------------
+ */
+int buildin_getareausers_sub(struct block_list *bl,va_list ap)
+{
+ int *users=va_arg(ap,int *);
+ (*users)++;
+ return 0;
+}
+int buildin_getareausers(struct script_state *st)
+{
+ char *str;
+ int m,x0,y0,x1,y1,users=0;
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ x0=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ y0=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ x1=conv_num(st,& (st->stack->stack_data[st->start+5]));
+ y1=conv_num(st,& (st->stack->stack_data[st->start+6]));
+ if( (m=map_mapname2mapid(str))< 0){
+ push_val(st->stack,C_INT,-1);
+ return 0;
+ }
+ map_foreachinarea(buildin_getareausers_sub,
+ m,x0,y0,x1,y1,BL_PC,&users);
+ push_val(st->stack,C_INT,users);
+ return 0;
+}
+
+/*==========================================
+ * エリア指定ドロップアイテム数所得
+ *------------------------------------------
+ */
+int buildin_getareadropitem_sub(struct block_list *bl,va_list ap)
+{
+ int item=va_arg(ap,int);
+ int *amount=va_arg(ap,int *);
+ struct flooritem_data *drop=(struct flooritem_data *)bl;
+
+ if(drop->item_data.nameid==item)
+ (*amount)+=drop->item_data.amount;
+
+ return 0;
+}
+int buildin_getareadropitem(struct script_state *st)
+{
+ char *str;
+ int m,x0,y0,x1,y1,item,amount=0;
+ struct script_data *data;
+
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ x0=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ y0=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ x1=conv_num(st,& (st->stack->stack_data[st->start+5]));
+ y1=conv_num(st,& (st->stack->stack_data[st->start+6]));
+
+ data=&(st->stack->stack_data[st->start+7]);
+ get_val(st,data);
+ if( data->type==C_STR || data->type==C_CONSTSTR ){
+ const char *name=conv_str(st,data);
+ struct item_data *item_data = itemdb_searchname(name);
+ item=512;
+ if( item_data )
+ item=item_data->nameid;
+ }else
+ item=conv_num(st,data);
+
+ if( (m=map_mapname2mapid(str))< 0){
+ push_val(st->stack,C_INT,-1);
+ return 0;
+ }
+ map_foreachinarea(buildin_getareadropitem_sub,
+ m,x0,y0,x1,y1,BL_ITEM,item,&amount);
+ push_val(st->stack,C_INT,amount);
+ return 0;
+}
+/*==========================================
+ * NPCの有効化
+ *------------------------------------------
+ */
+int buildin_enablenpc(struct script_state *st)
+{
+ char *str;
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ npc_enable(str,1);
+ return 0;
+}
+/*==========================================
+ * NPCの無効化
+ *------------------------------------------
+ */
+int buildin_disablenpc(struct script_state *st)
+{
+ char *str;
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ npc_enable(str,0);
+ return 0;
+}
+
+int buildin_enablearena(struct script_state *st) // Added by RoVeRT
+{
+ struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
+ struct chat_data *cd;
+
+
+ if(nd==NULL || (cd=(struct chat_data *)map_id2bl(nd->chat_id))==NULL)
+ return 0;
+
+ npc_enable(nd->name,1);
+ nd->arenaflag=1;
+
+ if(cd->users>=cd->trigger && cd->npc_event[0])
+ npc_timer_event(cd->npc_event);
+
+ return 0;
+}
+int buildin_disablearena(struct script_state *st) // Added by RoVeRT
+{
+ struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
+ nd->arenaflag=0;
+
+ return 0;
+}
+/*==========================================
+ * 隠れているNPCの表示
+ *------------------------------------------
+ */
+int buildin_hideoffnpc(struct script_state *st)
+{
+ char *str;
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ npc_enable(str,2);
+ return 0;
+}
+/*==========================================
+ * NPCをハイディング
+ *------------------------------------------
+ */
+int buildin_hideonnpc(struct script_state *st)
+{
+ char *str;
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ npc_enable(str,4);
+ return 0;
+}
+/*==========================================
+ * 状態異常にかかる
+ *------------------------------------------
+ */
+int buildin_sc_start(struct script_state *st)
+{
+ struct block_list *bl;
+ int type,tick,val1;
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ tick=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ val1=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ if( st->end>st->start+5 ) //指定したキャラを状態異常にする
+ bl = map_id2bl(conv_num(st,& (st->stack->stack_data[st->start+5])));
+ else
+ bl = map_id2bl(st->rid);
+ if(bl->type == BL_PC && ((struct map_session_data *)bl)->state.potionpitcher_flag)
+ bl = map_id2bl(((struct map_session_data *)bl)->skilltarget);
+ skill_status_change_start(bl,type,val1,0,0,0,tick,0);
+ return 0;
+}
+
+/*==========================================
+ * 状態異常にかかる(確率指定)
+ *------------------------------------------
+ */
+int buildin_sc_start2(struct script_state *st)
+{
+ struct block_list *bl;
+ int type,tick,val1,per;
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ tick=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ val1=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ per=conv_num(st,& (st->stack->stack_data[st->start+5]));
+ if( st->end>st->start+6 ) //指定したキャラを状態異常にする
+ bl = map_id2bl(conv_num(st,& (st->stack->stack_data[st->start+6])));
+ else
+ bl = map_id2bl(st->rid);
+ if(bl->type == BL_PC && ((struct map_session_data *)bl)->state.potionpitcher_flag)
+ bl = map_id2bl(((struct map_session_data *)bl)->skilltarget);
+ if(rand()%10000 < per)
+ skill_status_change_start(bl,type,val1,0,0,0,tick,0);
+ return 0;
+}
+
+/*==========================================
+ * 状態異常が直る
+ *------------------------------------------
+ */
+int buildin_sc_end(struct script_state *st)
+{
+ struct block_list *bl;
+ int type;
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ bl = map_id2bl(st->rid);
+ if(bl->type == BL_PC && ((struct map_session_data *)bl)->state.potionpitcher_flag)
+ bl = map_id2bl(((struct map_session_data *)bl)->skilltarget);
+ skill_status_change_end(bl,type,-1);
+// if(battle_config.etc_log)
+// printf("sc_end : %d %d\n",st->rid,type);
+ return 0;
+}
+/*==========================================
+ * 状態異常耐性を計算した確率を返す
+ *------------------------------------------
+ */
+int buildin_getscrate(struct script_state *st)
+{
+ struct block_list *bl;
+ int sc_def=100,sc_def_mdef2,sc_def_vit2,sc_def_int2,sc_def_luk2;
+ int type,rate,luk;
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ rate=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ if( st->end>st->start+4 ) //指定したキャラの耐性を計算する
+ bl = map_id2bl(conv_num(st,& (st->stack->stack_data[st->start+6])));
+ else
+ bl = map_id2bl(st->rid);
+
+ luk = battle_get_luk(bl);
+ sc_def_mdef2=100 - (3 + battle_get_mdef(bl) + luk/3);
+ sc_def_vit2=100 - (3 + battle_get_vit(bl) + luk/3);
+ sc_def_int2=100 - (3 + battle_get_int(bl) + luk/3);
+ sc_def_luk2=100 - (3 + luk);
+
+ if(type==SC_STONE || type==SC_FREEZE)
+ sc_def=sc_def_mdef2;
+ else if(type==SC_STAN || type==SC_POISON || type==SC_SILENCE)
+ sc_def=sc_def_vit2;
+ else if(type==SC_SLEEP || type==SC_CONFUSION || type==SC_BLIND)
+ sc_def=sc_def_int2;
+ else if(type==SC_CURSE)
+ sc_def=sc_def_luk2;
+
+ rate=rate*sc_def/100;
+ push_val(st->stack,C_INT,rate);
+
+ return 0;
+
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_debugmes(struct script_state *st)
+{
+ conv_str(st,& (st->stack->stack_data[st->start+2]));
+ printf("script debug : %d %d : %s\n",st->rid,st->oid,st->stack->stack_data[st->start+2].u.str);
+ return 0;
+}
+
+/*==========================================
+ *捕獲アイテム使用
+ *------------------------------------------
+ */
+int buildin_catchpet(struct script_state *st)
+{
+ int pet_id;
+ struct map_session_data *sd;
+ pet_id= conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sd=script_rid2sd(st);
+ pet_catch_process1(sd,pet_id);
+ return 0;
+}
+
+/*==========================================
+ *携帯卵孵化機使用
+ *------------------------------------------
+ */
+int buildin_birthpet(struct script_state *st)
+{
+ struct map_session_data *sd;
+ sd=script_rid2sd(st);
+ clif_sendegg(sd);
+ return 0;
+}
+
+/*==========================================
+ * Added - AppleGirl For Advanced Classes, (Updated for Cleaner Script Purposes)
+ *------------------------------------------
+ */
+int buildin_resetlvl(struct script_state *st)
+{
+ struct map_session_data *sd;
+
+ int type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+
+ sd=script_rid2sd(st);
+ pc_resetlvl(sd,type);
+ return 0;
+}
+/*==========================================
+ * ステータスリセット
+ *------------------------------------------
+ */
+int buildin_resetstatus(struct script_state *st)
+{
+ struct map_session_data *sd;
+ sd=script_rid2sd(st);
+ pc_resetstate(sd);
+ return 0;
+}
+
+/*==========================================
+ * スキルリセット
+ *------------------------------------------
+ */
+int buildin_resetskill(struct script_state *st)
+{
+ struct map_session_data *sd;
+ sd=script_rid2sd(st);
+ pc_resetskill(sd);
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int buildin_changebase(struct script_state *st)
+{
+ struct map_session_data *sd=NULL;
+ int vclass;
+
+ if( st->end>st->start+3 )
+ sd=map_id2sd(conv_num(st,& (st->stack->stack_data[st->start+3])));
+ else
+ sd=script_rid2sd(st);
+
+ if(sd == NULL)
+ return 0;
+
+ vclass = conv_num(st,& (st->stack->stack_data[st->start+2]));
+ if(vclass == 22 && !battle_config.wedding_modifydisplay)
+ return 0;
+
+// if(vclass==22) {
+// pc_unequipitem(sd,sd->equip_index[9],0); // 装備外
+// }
+
+ sd->view_class = vclass;
+
+ return 0;
+}
+
+/*==========================================
+ * 性別変換
+ *------------------------------------------
+ */
+int buildin_changesex(struct script_state *st) {
+ struct map_session_data *sd = NULL;
+ sd = script_rid2sd(st);
+
+ if (sd->status.sex == 0) {
+ sd->status.sex = 1;
+ sd->sex = 1;
+ if (sd->status.class == 20 || sd->status.class == 4021)
+ sd->status.class -= 1;
+ } else if (sd->status.sex == 1) {
+ sd->status.sex = 0;
+ sd->sex = 0;
+ if(sd->status.class == 19 || sd->status.class == 4020)
+ sd->status.class += 1;
+ }
+ chrif_char_ask_name(-1, sd->status.name, 5, 0, 0, 0, 0, 0, 0); // type: 5 - changesex
+ chrif_save(sd);
+ return 0;
+}
+
+/*==========================================
+ * npcチャット作成
+ *------------------------------------------
+ */
+int buildin_waitingroom(struct script_state *st)
+{
+ char *name,*ev="";
+ int limit, trigger = 0,pub=1;
+ name=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ limit= conv_num(st,& (st->stack->stack_data[st->start+3]));
+ if(limit==0)
+ pub=3;
+
+ if( (st->end > st->start+5) ){
+ struct script_data* data=&(st->stack->stack_data[st->start+5]);
+ get_val(st,data);
+ if(data->type==C_INT){
+ // 新Athena仕様(旧Athena仕様と互換性あり)
+ ev=conv_str(st,& (st->stack->stack_data[st->start+4]));
+ trigger=conv_num(st,& (st->stack->stack_data[st->start+5]));
+ }else{
+ // eathena仕様
+ trigger=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ ev=conv_str(st,& (st->stack->stack_data[st->start+5]));
+ }
+ }else{
+ // 旧Athena仕様
+ if( st->end > st->start+4 )
+ ev=conv_str(st,& (st->stack->stack_data[st->start+4]));
+ }
+ chat_createnpcchat( (struct npc_data *)map_id2bl(st->oid),
+ limit,pub,trigger,name,strlen(name)+1,ev);
+ return 0;
+}
+/*==========================================
+ * npcチャット削除
+ *------------------------------------------
+ */
+int buildin_delwaitingroom(struct script_state *st)
+{
+ struct npc_data *nd;
+ if( st->end > st->start+2 )
+ nd=npc_name2id(conv_str(st,& (st->stack->stack_data[st->start+2])));
+ else
+ nd=(struct npc_data *)map_id2bl(st->oid);
+ chat_deletenpcchat(nd);
+ return 0;
+}
+/*==========================================
+ * npcチャット全員蹴り出す
+ *------------------------------------------
+ */
+int buildin_waitingroomkickall(struct script_state *st)
+{
+ struct npc_data *nd;
+ struct chat_data *cd;
+
+ if( st->end > st->start+2 )
+ nd=npc_name2id(conv_str(st,& (st->stack->stack_data[st->start+2])));
+ else
+ nd=(struct npc_data *)map_id2bl(st->oid);
+
+ if(nd==NULL || (cd=(struct chat_data *)map_id2bl(nd->chat_id))==NULL )
+ return 0;
+ chat_npckickall(cd);
+ return 0;
+}
+
+/*==========================================
+ * npcチャットイベント有効化
+ *------------------------------------------
+ */
+int buildin_enablewaitingroomevent(struct script_state *st)
+{
+ struct npc_data *nd;
+ struct chat_data *cd;
+
+ if( st->end > st->start+2 )
+ nd=npc_name2id(conv_str(st,& (st->stack->stack_data[st->start+2])));
+ else
+ nd=(struct npc_data *)map_id2bl(st->oid);
+
+ if(nd==NULL || (cd=(struct chat_data *)map_id2bl(nd->chat_id))==NULL )
+ return 0;
+ chat_enableevent(cd);
+ return 0;
+}
+
+/*==========================================
+ * npcチャットイベント無効化
+ *------------------------------------------
+ */
+int buildin_disablewaitingroomevent(struct script_state *st)
+{
+ struct npc_data *nd;
+ struct chat_data *cd;
+
+ if( st->end > st->start+2 )
+ nd=npc_name2id(conv_str(st,& (st->stack->stack_data[st->start+2])));
+ else
+ nd=(struct npc_data *)map_id2bl(st->oid);
+
+ if(nd==NULL || (cd=(struct chat_data *)map_id2bl(nd->chat_id))==NULL )
+ return 0;
+ chat_disableevent(cd);
+ return 0;
+}
+/*==========================================
+ * npcチャット状態所得
+ *------------------------------------------
+ */
+int buildin_getwaitingroomstate(struct script_state *st)
+{
+ struct npc_data *nd;
+ struct chat_data *cd;
+ int val=0,type;
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ if( st->end > st->start+3 )
+ nd=npc_name2id(conv_str(st,& (st->stack->stack_data[st->start+3])));
+ else
+ nd=(struct npc_data *)map_id2bl(st->oid);
+
+ if(nd==NULL || (cd=(struct chat_data *)map_id2bl(nd->chat_id))==NULL ){
+ push_val(st->stack,C_INT,-1);
+ return 0;
+ }
+
+ switch(type){
+ case 0: val=cd->users; break;
+ case 1: val=cd->limit; break;
+ case 2: val=cd->trigger&0x7f; break;
+ case 3: val=((cd->trigger&0x80)>0); break;
+ case 32: val=(cd->users >= cd->limit); break;
+ case 33: val=(cd->users >= cd->trigger); break;
+
+ case 4:
+ push_str(st->stack,C_CONSTSTR,cd->title);
+ return 0;
+ case 5:
+ push_str(st->stack,C_CONSTSTR,cd->pass);
+ return 0;
+ case 16:
+ push_str(st->stack,C_CONSTSTR,cd->npc_event);
+ return 0;
+ }
+ push_val(st->stack,C_INT,val);
+ return 0;
+}
+
+/*==========================================
+ * チャットメンバー(規定人数)ワープ
+ *------------------------------------------
+ */
+int buildin_warpwaitingpc(struct script_state *st)
+{
+ int x,y,i,n;
+ char *str;
+ struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
+ struct chat_data *cd;
+
+ if(nd==NULL || (cd=(struct chat_data *)map_id2bl(nd->chat_id))==NULL )
+ return 0;
+
+ n=cd->trigger&0x7f;
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ x=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ y=conv_num(st,& (st->stack->stack_data[st->start+4]));
+
+ if( st->end > st->start+5 )
+ n=conv_num(st,& (st->stack->stack_data[st->start+5]));
+
+ for(i=0;i<n;i++){
+ struct map_session_data *sd=cd->usersd[0]; // リスト先頭のPCを次々に。
+
+ mapreg_setreg(add_str("$@warpwaitingpc")+(i<<24),sd->bl.id);
+
+ if(strcmp(str,"Random")==0)
+ pc_randomwarp(sd,3);
+ else if(strcmp(str,"SavePoint")==0){
+ if(map[sd->bl.m].flag.noteleport) // テレポ禁止
+ return 0;
+
+ pc_setpos(sd,sd->status.save_point.map,
+ sd->status.save_point.x,sd->status.save_point.y,3);
+ }else
+ pc_setpos(sd,str,x,y,0);
+ }
+ mapreg_setreg(add_str("$@warpwaitingpcnum"),n);
+ return 0;
+}
+/*==========================================
+ * RIDのアタッチ
+ *------------------------------------------
+ */
+int buildin_attachrid(struct script_state *st)
+{
+ st->rid=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ push_val(st->stack,C_INT, (map_id2sd(st->rid)!=NULL));
+ return 0;
+}
+/*==========================================
+ * RIDのデタッチ
+ *------------------------------------------
+ */
+int buildin_detachrid(struct script_state *st)
+{
+ st->rid=0;
+ return 0;
+}
+/*==========================================
+ * 存在チェック
+ *------------------------------------------
+ */
+int buildin_isloggedin(struct script_state *st)
+{
+ push_val(st->stack,C_INT, map_id2sd(
+ conv_num(st,& (st->stack->stack_data[st->start+2])) )!=NULL );
+ return 0;
+}
+
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+enum { MF_NOMEMO,MF_NOTELEPORT,MF_NOSAVE,MF_NOBRANCH,MF_NOPENALTY,MF_NOZENYPENALTY,MF_PVP,MF_PVP_NOPARTY,MF_PVP_NOGUILD,MF_GVG,MF_GVG_NOPARTY,MF_NOTRADE,MF_NOSKILL, MF_NOWARP,MF_NOPVP,MF_NOICEWALL,
+ MF_SNOW, MF_FOG, MF_SAKURA, MF_LEAVES, MF_RAIN };
+
+int buildin_setmapflagnosave(struct script_state *st)
+{
+ int m,x,y;
+ char *str,*str2;
+
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ str2=conv_str(st,& (st->stack->stack_data[st->start+3]));
+ x=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ y=conv_num(st,& (st->stack->stack_data[st->start+5]));
+ m = map_mapname2mapid(str);
+ if(m >= 0) {
+ map[m].flag.nosave=1;
+ memcpy(map[m].save.map,str2,16);
+ map[m].save.x=x;
+ map[m].save.y=y;
+ }
+
+ return 0;
+}
+
+int buildin_setmapflag(struct script_state *st)
+{
+ int m,i;
+ char *str;
+
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ i=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ m = map_mapname2mapid(str);
+ if(m >= 0) {
+ switch(i) {
+ case MF_NOMEMO:
+ map[m].flag.nomemo=1;
+ break;
+ case MF_NOTELEPORT:
+ map[m].flag.noteleport=1;
+ break;
+ case MF_NOBRANCH:
+ map[m].flag.nobranch=1;
+ break;
+ case MF_NOPENALTY:
+ map[m].flag.nopenalty=1;
+ break;
+ case MF_PVP_NOPARTY:
+ map[m].flag.pvp_noparty=1;
+ break;
+ case MF_PVP_NOGUILD:
+ map[m].flag.pvp_noguild=1;
+ break;
+ case MF_GVG_NOPARTY:
+ map[m].flag.gvg_noparty=1;
+ break;
+ case MF_NOZENYPENALTY:
+ map[m].flag.nozenypenalty=1;
+ break;
+ case MF_NOTRADE:
+ map[m].flag.notrade=1;
+ break;
+ case MF_NOSKILL:
+ map[m].flag.noskill=1;
+ break;
+ case MF_NOWARP:
+ map[m].flag.nowarp=1;
+ break;
+ case MF_NOPVP:
+ map[m].flag.nopvp=1;
+ break;
+ case MF_NOICEWALL: // [Valaris]
+ map[m].flag.noicewall=1;
+ break;
+ case MF_SNOW: // [Valaris]
+ map[m].flag.snow=1;
+ break;
+ case MF_FOG: // [Valaris]
+ map[m].flag.fog=1;
+ break;
+ case MF_SAKURA: // [Valaris]
+ map[m].flag.sakura=1;
+ break;
+ case MF_LEAVES: // [Valaris]
+ map[m].flag.leaves=1;
+ break;
+ case MF_RAIN: // [Valaris]
+ map[m].flag.rain=1;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int buildin_removemapflag(struct script_state *st)
+{
+ int m,i;
+ char *str;
+
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ i=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ m = map_mapname2mapid(str);
+ if(m >= 0) {
+ switch(i) {
+ case MF_NOMEMO:
+ map[m].flag.nomemo=0;
+ break;
+ case MF_NOTELEPORT:
+ map[m].flag.noteleport=0;
+ break;
+ case MF_NOSAVE:
+ map[m].flag.nosave=0;
+ break;
+ case MF_NOBRANCH:
+ map[m].flag.nobranch=0;
+ break;
+ case MF_NOPENALTY:
+ map[m].flag.nopenalty=0;
+ break;
+ case MF_PVP_NOPARTY:
+ map[m].flag.pvp_noparty=0;
+ break;
+ case MF_PVP_NOGUILD:
+ map[m].flag.pvp_noguild=0;
+ break;
+ case MF_GVG_NOPARTY:
+ map[m].flag.gvg_noparty=0;
+ break;
+ case MF_NOZENYPENALTY:
+ map[m].flag.nozenypenalty=0;
+ break;
+ case MF_NOSKILL:
+ map[m].flag.noskill=0;
+ break;
+ case MF_NOWARP:
+ map[m].flag.nowarp=0;
+ break;
+ case MF_NOPVP:
+ map[m].flag.nopvp=0;
+ break;
+ case MF_NOICEWALL: // [Valaris]
+ map[m].flag.noicewall=0;
+ break;
+ case MF_SNOW: // [Valaris]
+ map[m].flag.snow=0;
+ break;
+ case MF_FOG: // [Valaris]
+ map[m].flag.fog=0;
+ break;
+ case MF_SAKURA: // [Valaris]
+ map[m].flag.sakura=0;
+ break;
+ case MF_LEAVES: // [Valaris]
+ map[m].flag.leaves=0;
+ break;
+ case MF_RAIN: // [Valaris]
+ map[m].flag.rain=0;
+ break;
+
+ }
+ }
+
+ return 0;
+}
+
+int buildin_pvpon(struct script_state *st)
+{
+ int m,i;
+ char *str;
+ struct map_session_data *pl_sd=NULL;
+
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ m = map_mapname2mapid(str);
+ if(m >= 0 && !map[m].flag.pvp && !map[m].flag.nopvp) {
+ map[m].flag.pvp = 1;
+ clif_send0199(m,1);
+
+ if(battle_config.pk_mode) // disable ranking functions if pk_mode is on [Valaris]
+ return 0;
+
+ for(i=0;i<fd_max;i++){ //人数分ループ
+ if(session[i] && (pl_sd=session[i]->session_data) && pl_sd->state.auth){
+ if(m == pl_sd->bl.m && pl_sd->pvp_timer == -1) {
+ pl_sd->pvp_timer=add_timer(gettick()+200,pc_calc_pvprank_timer,pl_sd->bl.id,0);
+ pl_sd->pvp_rank=0;
+ pl_sd->pvp_lastusers=0;
+ pl_sd->pvp_point=5;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+int buildin_pvpoff(struct script_state *st)
+{
+ int m,i;
+ char *str;
+ struct map_session_data *pl_sd=NULL;
+
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ m = map_mapname2mapid(str);
+ if(m >= 0 && map[m].flag.pvp && map[m].flag.nopvp) {
+ map[m].flag.pvp = 0;
+ clif_send0199(m,0);
+
+ if(battle_config.pk_mode) // disable ranking options if pk_mode is on [Valaris]
+ return 0;
+
+ for(i=0;i<fd_max;i++){ //人数分ループ
+ if(session[i] && (pl_sd=session[i]->session_data) && pl_sd->state.auth){
+ if(m == pl_sd->bl.m) {
+ clif_pvpset(pl_sd,0,0,2);
+ if(pl_sd->pvp_timer != -1) {
+ delete_timer(pl_sd->pvp_timer,pc_calc_pvprank_timer);
+ pl_sd->pvp_timer = -1;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+int buildin_gvgon(struct script_state *st)
+{
+ int m;
+ char *str;
+
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ m = map_mapname2mapid(str);
+ if(m >= 0 && !map[m].flag.gvg) {
+ map[m].flag.gvg = 1;
+ clif_send0199(m,3);
+ }
+
+ return 0;
+}
+int buildin_gvgoff(struct script_state *st)
+{
+ int m;
+ char *str;
+
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ m = map_mapname2mapid(str);
+ if(m >= 0 && map[m].flag.gvg) {
+ map[m].flag.gvg = 0;
+ clif_send0199(m,0);
+ }
+
+ return 0;
+}
+/*==========================================
+ * NPCエモーション
+ *------------------------------------------
+ */
+
+int buildin_emotion(struct script_state *st)
+{
+ int type;
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ if(type < 0 || type > 100)
+ return 0;
+ clif_emotion(map_id2bl(st->oid),type);
+ return 0;
+}
+
+int buildin_maprespawnguildid_sub(struct block_list *bl,va_list ap)
+{
+ int g_id=va_arg(ap,int);
+ int flag=va_arg(ap,int);
+ struct map_session_data *sd=NULL;
+ struct mob_data *md=NULL;
+
+ if(bl->type == BL_PC)
+ sd=(struct map_session_data*)bl;
+ if(bl->type == BL_MOB)
+ md=(struct mob_data *)bl;
+
+ if(sd){
+ if((sd->status.guild_id == g_id) && (flag&1))
+ pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3);
+ else if((sd->status.guild_id != g_id) && (flag&2))
+ pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3);
+ else if (sd->status.guild_id == 0) // Warp out players not in guild [Valaris]
+ pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3); // end addition [Valaris]
+ }
+ if(md && flag&4){
+ if(md->class < 1285 || md->class > 1288)
+ mob_delete(md);
+ }
+ return 0;
+}
+int buildin_maprespawnguildid(struct script_state *st)
+{
+ char *mapname=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ int g_id=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ int flag=conv_num(st,& (st->stack->stack_data[st->start+4]));
+
+ int m=map_mapname2mapid(mapname);
+
+ if(m) map_foreachinarea(buildin_maprespawnguildid_sub,m,0,0,map[m].xs-1,map[m].ys-1,BL_NUL,g_id,flag);
+ return 0;
+}
+
+int buildin_agitstart(struct script_state *st)
+{
+ if(agit_flag==1) return 1; // Agit already Start.
+ agit_flag=1;
+ guild_agit_start();
+ return 0;
+}
+
+int buildin_agitend(struct script_state *st)
+{
+ if(agit_flag==0) return 1; // Agit already End.
+ agit_flag=0;
+ guild_agit_end();
+ return 0;
+}
+/*==========================================
+ * agitcheck 1; // choice script
+ * if(@agit_flag == 1) goto agit;
+ * if(agitcheck(0) == 1) goto agit;
+ *------------------------------------------
+ */
+int buildin_agitcheck(struct script_state *st)
+{
+ struct map_session_data *sd;
+ int cond;
+
+ sd=script_rid2sd(st);
+ cond=conv_num(st,& (st->stack->stack_data[st->start+2]));
+
+ if(cond == 0) {
+ if (agit_flag==1) push_val(st->stack,C_INT,1);
+ if (agit_flag==0) push_val(st->stack,C_INT,0);
+ } else {
+ if (agit_flag==1) pc_setreg(sd,add_str("@agit_flag"),1);
+ if (agit_flag==0) pc_setreg(sd,add_str("@agit_flag"),0);
+ }
+ return 0;
+}
+int buildin_flagemblem(struct script_state *st)
+{
+ int g_id=conv_num(st,& (st->stack->stack_data[st->start+2]));
+
+ if(g_id < 0) return 0;
+
+// printf("Script.c: [FlagEmblem] GuildID=%d, Emblem=%d.\n", g->guild_id, g->emblem_id);
+ ((struct npc_data *)map_id2bl(st->oid))->u.scr.guild_id = g_id;
+ return 1;
+}
+
+int buildin_getcastlename(struct script_state *st)
+{
+ char *mapname=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ struct guild_castle *gc;
+ int i;
+ char *buf=NULL;
+ for(i=0;i<MAX_GUILDCASTLE;i++){
+ if( (gc=guild_castle_search(i)) != NULL ){
+ if(strcmp(mapname,gc->map_name)==0){
+ buf=(char *)aCalloc(24,sizeof(char));
+ strncpy(buf,gc->castle_name,24);
+ break;
+ }
+ }
+ }
+ if(buf)
+ push_str(st->stack,C_STR,buf);
+ else
+ push_str(st->stack,C_CONSTSTR,"");
+ return 0;
+}
+
+int buildin_getcastledata(struct script_state *st)
+{
+ char *mapname=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ int index=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ char *event=NULL;
+ struct guild_castle *gc;
+ int i,j;
+
+ if( st->end>st->start+4 && index==0){
+ for(i=0,j=-1;i<MAX_GUILDCASTLE;i++)
+ if( (gc=guild_castle_search(i)) != NULL &&
+ strcmp(mapname,gc->map_name)==0 )
+ j=i;
+ if(j>=0){
+ event=conv_str(st,& (st->stack->stack_data[st->start+4]));
+ guild_addcastleinfoevent(j,17,event);
+ }
+ }
+
+ for(i=0;i<MAX_GUILDCASTLE;i++){
+ if( (gc=guild_castle_search(i)) != NULL ){
+ if(strcmp(mapname,gc->map_name)==0){
+ switch(index){
+ case 0: for(j=1;j<26;j++) guild_castledataload(gc->castle_id,j); break; // Initialize[AgitInit]
+ case 1: push_val(st->stack,C_INT,gc->guild_id); break;
+ case 2: push_val(st->stack,C_INT,gc->economy); break;
+ case 3: push_val(st->stack,C_INT,gc->defense); break;
+ case 4: push_val(st->stack,C_INT,gc->triggerE); break;
+ case 5: push_val(st->stack,C_INT,gc->triggerD); break;
+ case 6: push_val(st->stack,C_INT,gc->nextTime); break;
+ case 7: push_val(st->stack,C_INT,gc->payTime); break;
+ case 8: push_val(st->stack,C_INT,gc->createTime); break;
+ case 9: push_val(st->stack,C_INT,gc->visibleC); break;
+ case 10: push_val(st->stack,C_INT,gc->visibleG0); break;
+ case 11: push_val(st->stack,C_INT,gc->visibleG1); break;
+ case 12: push_val(st->stack,C_INT,gc->visibleG2); break;
+ case 13: push_val(st->stack,C_INT,gc->visibleG3); break;
+ case 14: push_val(st->stack,C_INT,gc->visibleG4); break;
+ case 15: push_val(st->stack,C_INT,gc->visibleG5); break;
+ case 16: push_val(st->stack,C_INT,gc->visibleG6); break;
+ case 17: push_val(st->stack,C_INT,gc->visibleG7); break;
+ case 18: push_val(st->stack,C_INT,gc->Ghp0); break;
+ case 19: push_val(st->stack,C_INT,gc->Ghp1); break;
+ case 20: push_val(st->stack,C_INT,gc->Ghp2); break;
+ case 21: push_val(st->stack,C_INT,gc->Ghp3); break;
+ case 22: push_val(st->stack,C_INT,gc->Ghp4); break;
+ case 23: push_val(st->stack,C_INT,gc->Ghp5); break;
+ case 24: push_val(st->stack,C_INT,gc->Ghp6); break;
+ case 25: push_val(st->stack,C_INT,gc->Ghp7); break;
+ default:
+ push_val(st->stack,C_INT,0); break;
+ }
+ return 0;
+ }
+ }
+ }
+ push_val(st->stack,C_INT,0);
+ return 0;
+}
+
+int buildin_setcastledata(struct script_state *st)
+{
+ char *mapname=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ int index=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ int value=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ struct guild_castle *gc;
+ int i;
+
+ for(i=0;i<MAX_GUILDCASTLE;i++){
+ if( (gc=guild_castle_search(i)) != NULL ){
+ if(strcmp(mapname,gc->map_name)==0){
+ // Save Data byself First
+ switch(index){
+ case 1: gc->guild_id = value; break;
+ case 2: gc->economy = value; break;
+ case 3: gc->defense = value; break;
+ case 4: gc->triggerE = value; break;
+ case 5: gc->triggerD = value; break;
+ case 6: gc->nextTime = value; break;
+ case 7: gc->payTime = value; break;
+ case 8: gc->createTime = value; break;
+ case 9: gc->visibleC = value; break;
+ case 10: gc->visibleG0 = value; break;
+ case 11: gc->visibleG1 = value; break;
+ case 12: gc->visibleG2 = value; break;
+ case 13: gc->visibleG3 = value; break;
+ case 14: gc->visibleG4 = value; break;
+ case 15: gc->visibleG5 = value; break;
+ case 16: gc->visibleG6 = value; break;
+ case 17: gc->visibleG7 = value; break;
+ case 18: gc->Ghp0 = value; break;
+ case 19: gc->Ghp1 = value; break;
+ case 20: gc->Ghp2 = value; break;
+ case 21: gc->Ghp3 = value; break;
+ case 22: gc->Ghp4 = value; break;
+ case 23: gc->Ghp5 = value; break;
+ case 24: gc->Ghp6 = value; break;
+ case 25: gc->Ghp7 = value; break;
+ default: return 0;
+ }
+ guild_castledatasave(gc->castle_id,index,value);
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/* =====================================================================
+ * ギルド情報を要求する
+ * ---------------------------------------------------------------------
+ */
+int buildin_requestguildinfo(struct script_state *st)
+{
+ int guild_id=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ char *event=NULL;
+
+ if( st->end>st->start+3 )
+ event=conv_str(st,& (st->stack->stack_data[st->start+3]));
+
+ if(guild_id>0)
+ guild_npc_request_info(guild_id,event);
+ return 0;
+}
+
+/* =====================================================================
+ * カードの数を得る
+ * ---------------------------------------------------------------------
+ */
+int buildin_getequipcardcnt(struct script_state *st)
+{
+ int i,num;
+ struct map_session_data *sd;
+ int c=4;
+
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sd=script_rid2sd(st);
+ i=pc_checkequip(sd,equip[num-1]);
+ if(sd->status.inventory[i].card[0] == 0x00ff){ // 製造武器はカードなし
+ push_val(st->stack,C_INT,0);
+ return 0;
+ }
+ do{
+ if( (sd->status.inventory[i].card[c-1] > 4000) &&
+ (sd->status.inventory[i].card[c-1] < 5000)){
+
+ push_val(st->stack,C_INT,(c));
+ return 0;
+ }
+ }while(c--);
+ push_val(st->stack,C_INT,0);
+ return 0;
+}
+
+/* ================================================================
+ * カード取り外し成功
+ * ----------------------------------------------------------------
+ */
+int buildin_successremovecards(struct script_state *st)
+{
+ int i,num,cardflag=0,flag;
+ struct map_session_data *sd;
+ struct item item_tmp;
+ int c=4;
+
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ sd=script_rid2sd(st);
+ i=pc_checkequip(sd,equip[num-1]);
+ if(sd->status.inventory[i].card[0]==0x00ff){ // 製造武器は処理しない
+ return 0;
+ }
+ do{
+ if( (sd->status.inventory[i].card[c-1] > 4000) &&
+ (sd->status.inventory[i].card[c-1] < 5000)){
+
+ cardflag = 1;
+ item_tmp.id=0,item_tmp.nameid=sd->status.inventory[i].card[c-1];
+ item_tmp.equip=0,item_tmp.identify=1,item_tmp.refine=0;
+ item_tmp.attribute=0;
+ item_tmp.card[0]=0,item_tmp.card[1]=0,item_tmp.card[2]=0,item_tmp.card[3]=0;
+
+ if((flag=pc_additem(sd,&item_tmp,1))){ // 持てないならドロップ
+ clif_additem(sd,0,0,flag);
+ map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
+ }
+ }
+ }while(c--);
+
+ if(cardflag == 1){ // カードを取り除いたアイテム所得
+ flag=0;
+ item_tmp.id=0,item_tmp.nameid=sd->status.inventory[i].nameid;
+ item_tmp.equip=0,item_tmp.identify=1,item_tmp.refine=sd->status.inventory[i].refine;
+ item_tmp.attribute=sd->status.inventory[i].attribute;
+ item_tmp.card[0]=0,item_tmp.card[1]=0,item_tmp.card[2]=0,item_tmp.card[3]=0;
+ pc_delitem(sd,i,1,0);
+ if((flag=pc_additem(sd,&item_tmp,1))){ // もてないならドロップ
+ clif_additem(sd,0,0,flag);
+ map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
+ }
+ clif_misceffect(&sd->bl,3);
+ return 0;
+ }
+ return 0;
+}
+
+/* ================================================================
+ * カード取り外し失敗 slot,type
+ * type=0: 両方損失、1:カード損失、2:武具損失、3:損失無し
+ * ----------------------------------------------------------------
+ */
+int buildin_failedremovecards(struct script_state *st)
+{
+ int i,num,cardflag=0,flag,typefail;
+ struct map_session_data *sd;
+ struct item item_tmp;
+ int c=4;
+
+ num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ typefail=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ sd=script_rid2sd(st);
+ i=pc_checkequip(sd,equip[num-1]);
+ if(sd->status.inventory[i].card[0]==0x00ff){ // 製造武器は処理しない
+ return 0;
+ }
+ do{
+ if(( sd->status.inventory[i].card[c-1] > 4000) &&
+ (sd->status.inventory[i].card[c-1] < 5000)){
+
+ cardflag = 1;
+
+ if(typefail == 2){ // 武具のみ損失なら、カードは受け取らせる
+ item_tmp.id=0,item_tmp.nameid=sd->status.inventory[i].card[c-1];
+ item_tmp.equip=0,item_tmp.identify=1,item_tmp.refine=0;
+ item_tmp.attribute=0;
+ item_tmp.card[0]=0,item_tmp.card[1]=0,item_tmp.card[2]=0,item_tmp.card[3]=0;
+ if((flag=pc_additem(sd,&item_tmp,1))){
+ clif_additem(sd,0,0,flag);
+ map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
+ }
+ }
+ }
+ }while(c--);
+
+ if(cardflag == 1){
+
+ if(typefail == 0 || typefail == 2){ // 武具損失
+ pc_delitem(sd,i,1,0);
+ clif_misceffect(&sd->bl,2);
+ return 0;
+ }
+ if(typefail == 1){ // カードのみ損失(武具を返す)
+ flag=0;
+ item_tmp.id=0,item_tmp.nameid=sd->status.inventory[i].nameid;
+ item_tmp.equip=0,item_tmp.identify=1,item_tmp.refine=sd->status.inventory[i].refine;
+ item_tmp.attribute=sd->status.inventory[i].attribute;
+ item_tmp.card[0]=0,item_tmp.card[1]=0,item_tmp.card[2]=0,item_tmp.card[3]=0;
+ pc_delitem(sd,i,1,0);
+ if((flag=pc_additem(sd,&item_tmp,1))){
+ clif_additem(sd,0,0,flag);
+ map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
+ }
+ }
+ clif_misceffect(&sd->bl,2);
+ return 0;
+ }
+ return 0;
+}
+
+int buildin_mapwarp(struct script_state *st) // Added by RoVeRT
+{
+ int x,y,m;
+ char *str;
+ char *mapname;
+ int x0,y0,x1,y1;
+
+ mapname=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ x0=0;
+ y0=0;
+ x1=map[map_mapname2mapid(mapname)].xs;
+ y1=map[map_mapname2mapid(mapname)].ys;
+ str=conv_str(st,& (st->stack->stack_data[st->start+3]));
+ x=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ y=conv_num(st,& (st->stack->stack_data[st->start+5]));
+
+ if( (m=map_mapname2mapid(mapname))< 0)
+ return 0;
+
+ map_foreachinarea(buildin_areawarp_sub,
+ m,x0,y0,x1,y1,BL_PC, str,x,y );
+ return 0;
+}
+
+int buildin_cmdothernpc(struct script_state *st) // Added by RoVeRT
+{
+ char *npc,*command;
+
+ npc=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ command=conv_str(st,& (st->stack->stack_data[st->start+3]));
+
+ npc_command(map_id2sd(st->rid),npc,command);
+ return 0;
+}
+
+int buildin_inittimer(struct script_state *st) // Added by RoVeRT
+{
+// struct npc_data *nd=(struct npc_data*)map_id2bl(st->oid);
+
+// nd->lastaction=nd->timer=gettick();
+ npc_do_ontimer(st->oid, map_id2sd(st->rid), 1);
+
+ return 0;
+}
+
+int buildin_stoptimer(struct script_state *st) // Added by RoVeRT
+{
+// struct npc_data *nd=(struct npc_data*)map_id2bl(st->oid);
+
+// nd->lastaction=nd->timer=-1;
+ npc_do_ontimer(st->oid, map_id2sd(st->rid), 0);
+
+ return 0;
+}
+
+int buildin_mobcount_sub(struct block_list *bl,va_list ap) // Added by RoVeRT
+{
+ char *event=va_arg(ap,char *);
+ int *c=va_arg(ap,int *);
+
+ if(strcmp(event,((struct mob_data *)bl)->npc_event)==0)
+ (*c)++;
+ return 0;
+}
+
+int buildin_mobcount(struct script_state *st) // Added by RoVeRT
+{
+ char *mapname,*event;
+ int m,c=0;
+ mapname=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ event=conv_str(st,& (st->stack->stack_data[st->start+3]));
+
+ if( (m=map_mapname2mapid(mapname))<0 ) {
+ push_val(st->stack,C_INT,-1);
+ return 0;
+ }
+ map_foreachinarea(buildin_mobcount_sub,
+ m,0,0,map[m].xs,map[m].ys,BL_MOB, event,&c );
+
+ push_val(st->stack,C_INT, (c - 1));
+
+ return 0;
+}
+int buildin_marriage(struct script_state *st)
+{
+ char *partner=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ struct map_session_data *sd=script_rid2sd(st);
+ struct map_session_data *p_sd=map_nick2sd(partner);
+
+ if(sd==NULL || p_sd==NULL || pc_marriage(sd,p_sd) < 0){
+ push_val(st->stack,C_INT,0);
+ return 0;
+ }
+ push_val(st->stack,C_INT,1);
+ return 0;
+}
+int buildin_wedding_effect(struct script_state *st)
+{
+ struct map_session_data *sd=script_rid2sd(st);
+
+ if(sd==NULL)
+ return 0;
+ clif_wedding_effect(&sd->bl);
+ return 0;
+}
+int buildin_divorce(struct script_state *st)
+{
+ struct map_session_data *sd=script_rid2sd(st);
+ if(sd==NULL || pc_divorce(sd) < 0){
+ push_val(st->stack,C_INT,0);
+ return 0;
+ }
+ push_val(st->stack,C_INT,1);
+ return 0;
+}
+
+/*================================================
+ * Script for Displaying MOB Information [Valaris]
+ *------------------------------------------------
+ */
+int buildin_strmobinfo(struct script_state *st)
+{
+
+ int num=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ int class=conv_num(st,& (st->stack->stack_data[st->start+3]));
+
+ if(num<=0 || num>=8 || (class>=0 && class<=1000) || class >2000)
+ return 0;
+
+ if(num==1) {
+ char *buf;
+ buf=calloc(24, 1);
+ buf=mob_db[class].name;
+ push_str(st->stack,C_STR,buf);
+ return 0;
+ }
+ else if(num==2) {
+ char *buf;
+ buf=calloc(24, 1);
+ buf=mob_db[class].jname;
+ push_str(st->stack,C_STR,buf);
+ return 0;
+ }
+ else if(num==3)
+ push_val(st->stack,C_INT,mob_db[class].lv);
+ else if(num==4)
+ push_val(st->stack,C_INT,mob_db[class].max_hp);
+ else if(num==5)
+ push_val(st->stack,C_INT,mob_db[class].max_sp);
+ else if(num==6)
+ push_val(st->stack,C_INT,mob_db[class].base_exp);
+ else if(num==7)
+ push_val(st->stack,C_INT,mob_db[class].job_exp);
+ return 0;
+}
+
+/*==========================================
+ * Summon guardians [Valaris]
+ *------------------------------------------
+ */
+int buildin_guardian(struct script_state *st)
+{
+ int class=0,amount=1,x=0,y=0,guardian=0;
+ char *str,*map,*event="";
+
+ map =conv_str(st,& (st->stack->stack_data[st->start+2]));
+ x =conv_num(st,& (st->stack->stack_data[st->start+3]));
+ y =conv_num(st,& (st->stack->stack_data[st->start+4]));
+ str =conv_str(st,& (st->stack->stack_data[st->start+5]));
+ class=conv_num(st,& (st->stack->stack_data[st->start+6]));
+ amount=conv_num(st,& (st->stack->stack_data[st->start+7]));
+ event=conv_str(st,& (st->stack->stack_data[st->start+8]));
+ if( st->end>st->start+9 )
+ guardian=conv_num(st,& (st->stack->stack_data[st->start+9]));
+
+ mob_spawn_guardian(map_id2sd(st->rid),map,x,y,str,class,amount,event,guardian);
+
+ return 0;
+}
+
+/*================================================
+ * Script for Displaying Guardian Info [Valaris]
+ *------------------------------------------------
+ */
+int buildin_guardianinfo(struct script_state *st)
+{
+ int guardian=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ struct map_session_data *sd=script_rid2sd(st);
+ struct guild_castle *gc=guild_mapname2gc(map[sd->bl.m].name);
+
+ if(guardian==0 && gc->visibleG0 == 1) push_val(st->stack,C_INT,gc->Ghp0);
+ if(guardian==1 && gc->visibleG1 == 1) push_val(st->stack,C_INT,gc->Ghp1);
+ if(guardian==2 && gc->visibleG2 == 1) push_val(st->stack,C_INT,gc->Ghp2);
+ if(guardian==3 && gc->visibleG3 == 1) push_val(st->stack,C_INT,gc->Ghp3);
+ if(guardian==4 && gc->visibleG4 == 1) push_val(st->stack,C_INT,gc->Ghp4);
+ if(guardian==5 && gc->visibleG5 == 1) push_val(st->stack,C_INT,gc->Ghp5);
+ if(guardian==6 && gc->visibleG6 == 1) push_val(st->stack,C_INT,gc->Ghp6);
+ if(guardian==7 && gc->visibleG7 == 1) push_val(st->stack,C_INT,gc->Ghp7);
+ else push_val(st->stack,C_INT,-1);
+
+ return 0;
+}
+/*==========================================
+ * IDからItem名
+ *------------------------------------------
+ */
+int buildin_getitemname(struct script_state *st)
+{
+ int item_id;
+ struct item_data *i_data;
+ char *item_name;
+
+ item_id=conv_num(st,& (st->stack->stack_data[st->start+2]));
+
+ i_data = NULL;
+ i_data = itemdb_search(item_id);
+ item_name=(char *)aCalloc(24,sizeof(char));
+
+ strncpy(item_name,i_data->jname,23);
+ push_str(st->stack,C_STR,item_name);
+ return 0;
+}
+
+/*==========================================
+ * petskillbonus [Valaris]
+ *------------------------------------------
+ */
+
+int buildin_petskillbonus(struct script_state *st)
+{
+ int type,val,duration,timer;
+ struct pet_data *pd;
+
+ struct map_session_data *sd=script_rid2sd(st);
+
+ if(sd==NULL || sd->pd==NULL)
+ return 0;
+
+ pd=sd->pd;
+
+ if(pd==NULL)
+ return 0;
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ val=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ duration=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ timer=conv_num(st,& (st->stack->stack_data[st->start+5]));
+
+ pd->skillbonusduration=-1;
+ pd->skillbonustimer=-1;
+
+ pet_skill_bonus(sd,pd,type,val,duration,timer,0);
+
+ return 0;
+}
+
+/*==========================================
+ * pet looting [Valaris]
+ *------------------------------------------
+ */
+int buildin_petloot(struct script_state *st)
+{
+ int max;
+ struct pet_data *pd;
+
+ struct map_session_data *sd=script_rid2sd(st);
+ if(sd==NULL || sd->pd==NULL)
+ return 0;
+
+ pd=sd->pd;
+
+ if(pd==NULL)
+ return 0;
+
+ max=conv_num(st,& (st->stack->stack_data[st->start+2]));
+
+ if(!max)
+ return 0;
+
+ pd->loot=1;
+ pd->lootmax=max;
+
+ return 0;
+}
+/*==========================================
+ * PCの所持品情報読み取り
+ *------------------------------------------
+ */
+int buildin_getinventorylist(struct script_state *st)
+{
+ struct map_session_data *sd=script_rid2sd(st);
+ int i,j=0;
+ if(!sd) return 0;
+ for(i=0;i<MAX_INVENTORY;i++){
+ if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0){
+ pc_setreg(sd,add_str("@inventorylist_id")+(j<<24),sd->status.inventory[i].nameid);
+ pc_setreg(sd,add_str("@inventorylist_amount")+(j<<24),sd->status.inventory[i].amount);
+ pc_setreg(sd,add_str("@inventorylist_equip")+(j<<24),sd->status.inventory[i].equip);
+ pc_setreg(sd,add_str("@inventorylist_refine")+(j<<24),sd->status.inventory[i].refine);
+ pc_setreg(sd,add_str("@inventorylist_identify")+(j<<24),sd->status.inventory[i].identify);
+ pc_setreg(sd,add_str("@inventorylist_attribute")+(j<<24),sd->status.inventory[i].attribute);
+ pc_setreg(sd,add_str("@inventorylist_card1")+(j<<24),sd->status.inventory[i].card[0]);
+ pc_setreg(sd,add_str("@inventorylist_card2")+(j<<24),sd->status.inventory[i].card[1]);
+ pc_setreg(sd,add_str("@inventorylist_card3")+(j<<24),sd->status.inventory[i].card[2]);
+ pc_setreg(sd,add_str("@inventorylist_card4")+(j<<24),sd->status.inventory[i].card[3]);
+ j++;
+ }
+ }
+ pc_setreg(sd,add_str("@inventorylist_count"),j);
+ return 0;
+}
+
+int buildin_getskilllist(struct script_state *st)
+{
+ struct map_session_data *sd=script_rid2sd(st);
+ int i,j=0;
+ if(!sd) return 0;
+ for(i=0;i<MAX_SKILL;i++){
+ if(sd->status.skill[i].id > 0 && sd->status.skill[i].lv > 0){
+ pc_setreg(sd,add_str("@skilllist_id")+(j<<24),sd->status.skill[i].id);
+ pc_setreg(sd,add_str("@skilllist_lv")+(j<<24),sd->status.skill[i].lv);
+ pc_setreg(sd,add_str("@skilllist_flag")+(j<<24),sd->status.skill[i].flag);
+ j++;
+ }
+ }
+ pc_setreg(sd,add_str("@skilllist_count"),j);
+ return 0;
+}
+
+int buildin_clearitem(struct script_state *st)
+{
+ struct map_session_data *sd=script_rid2sd(st);
+ int i;
+ if(sd==NULL) return 0;
+ for (i=0; i<MAX_INVENTORY; i++) {
+ if (sd->status.inventory[i].amount)
+ pc_delitem(sd, i, sd->status.inventory[i].amount, 0);
+ }
+ return 0;
+}
+
+/*==========================================
+ * NPCクラスチェンジ
+ * classは変わりたいclass
+ * typeは通常0なのかな?
+ *------------------------------------------
+ */
+int buildin_classchange(struct script_state *st)
+{
+ int class,type;
+ struct block_list *bl=map_id2bl(st->oid);
+
+ if(bl==NULL) return 0;
+
+ class=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ type=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ clif_class_change(bl,class,type);
+ return 0;
+}
+
+/*==========================================
+ * NPCから発生するエフェクト
+ *------------------------------------------
+ */
+int buildin_misceffect(struct script_state *st)
+{
+ int type;
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ if(st->oid)
+ clif_misceffect2(map_id2bl(st->oid),type);
+ else{
+ struct map_session_data *sd=script_rid2sd(st);
+ if(sd)
+ clif_misceffect2(&sd->bl,type);
+ }
+ return 0;
+}
+/*==========================================
+ * サウンドエフェクト
+ *------------------------------------------
+ */
+int buildin_soundeffect(struct script_state *st)
+{
+ struct map_session_data *sd=script_rid2sd(st);
+ char *name;
+ int type=0;
+
+
+ name=conv_str(st,& (st->stack->stack_data[st->start+2]));
+ type=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ if(sd){
+ if(st->oid)
+ clif_soundeffect(sd,map_id2bl(st->oid),name,type);
+ else{
+ clif_soundeffect(sd,&sd->bl,name,type);
+ }
+ }
+ return 0;
+}
+/*==========================================
+ * pet status recovery [Valaris]
+ *------------------------------------------
+ */
+int buildin_petrecovery(struct script_state *st)
+{
+ struct pet_data *pd;
+
+ struct map_session_data *sd=script_rid2sd(st);
+
+ if(sd==NULL || sd->pd==NULL)
+ return 0;
+
+ pd=sd->pd;
+
+ if(pd==NULL)
+ return 0;
+
+ pd->skilltype=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ pd->skilltimer=conv_num(st,& (st->stack->stack_data[st->start+3]));
+
+ pd->skillbonustimer=add_timer(gettick()+pd->skilltimer*1000,pet_recovery_timer,sd->bl.id,0);
+
+ return 0;
+}
+
+/*==========================================
+ * pet healing [Valaris]
+ *------------------------------------------
+ */
+int buildin_petheal(struct script_state *st)
+
+{
+ struct pet_data *pd;
+ struct map_session_data *sd=script_rid2sd(st);
+
+ if(sd==NULL || sd->pd==NULL)
+ return 0;
+
+ pd=sd->pd;
+
+ if(pd==NULL)
+ return 0;
+
+ pd->skilltype=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ pd->skillval=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ pd->skilltimer=conv_num(st,& (st->stack->stack_data[st->start+4]));
+
+ pd->skillbonustimer=add_timer(gettick()+pd->skilltimer*1000,pet_heal_timer,sd->bl.id,0);
+
+ return 0;
+}
+
+/*==========================================
+ * pet magnificat [Valaris]
+ *------------------------------------------
+ */
+int buildin_petmag(struct script_state *st)
+{
+ struct pet_data *pd;
+ struct map_session_data *sd=script_rid2sd(st);
+
+ if(sd==NULL || sd->pd==NULL)
+ return 0;
+
+ pd=sd->pd;
+
+ if(pd==NULL)
+ return 0;
+
+ pd->skilltype=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ pd->skillduration=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ pd->skillval=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ pd->skilltimer=conv_num(st,& (st->stack->stack_data[st->start+5]));
+
+ pd->skillbonustimer=add_timer(gettick()+pd->skilltimer*1000,pet_mag_timer,sd->bl.id,0);
+
+ return 0;
+}
+
+/*==========================================
+ * pet attack skills [Valaris]
+ *------------------------------------------
+ */
+int buildin_petskillattack(struct script_state *st)
+{
+ struct pet_data *pd;
+ struct map_session_data *sd=script_rid2sd(st);
+
+ if(sd==NULL || sd->pd==NULL)
+ return 0;
+
+ pd=sd->pd;
+
+ if(pd==NULL)
+ return 0;
+
+ pd->skilltype=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ pd->skillval=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ pd->skillduration=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ pd->skilltimer=conv_num(st,& (st->stack->stack_data[st->start+5]));
+
+ pd->skillbonustimer=add_timer(gettick()+100,pet_skillattack_timer,sd->bl.id,0);
+
+ return 0;
+}
+/*==========================================
+ * NPC skill effects [Valaris]
+ *------------------------------------------
+ */
+int buildin_npcskilleffect(struct script_state *st)
+{
+ struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
+
+ int skillid=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ int skilllv=conv_num(st,& (st->stack->stack_data[st->start+3]));
+ int x=conv_num(st,& (st->stack->stack_data[st->start+4]));
+ int y=conv_num(st,& (st->stack->stack_data[st->start+5]));
+
+ clif_skill_poseffect(&nd->bl,skillid,skilllv,x,y,gettick());
+
+ return 0;
+}
+
+/*==========================================
+ * Special effects [Valaris]
+ *------------------------------------------
+ */
+int buildin_specialeffect(struct script_state *st)
+{
+ struct block_list *bl=map_id2bl(st->oid);
+
+ if(bl==NULL)
+ return 0;
+
+ clif_specialeffect(bl,conv_num(st,& (st->stack->stack_data[st->start+2])), 0);
+
+ return 0;
+}
+
+int buildin_specialeffect2(struct script_state *st)
+{
+ struct map_session_data *sd=script_rid2sd(st);
+
+ if(sd==NULL)
+ return 0;
+
+ clif_specialeffect(&sd->bl,conv_num(st,& (st->stack->stack_data[st->start+2])), 0);
+
+ return 0;
+}
+
+/*==========================================
+ * Nude [Valaris]
+ *------------------------------------------
+ */
+
+int buildin_nude(struct script_state *st)
+{
+ struct map_session_data *sd=script_rid2sd(st);
+ int i;
+
+ if(sd==NULL)
+ return 0;
+
+ for(i=0;i<11;i++)
+ if(sd->equip_index[i] >= 0)
+ pc_unequipitem(sd,sd->equip_index[i],1);
+
+ return 0;
+}
+
+/*==========================================
+ * gmcommand [MouseJstr]
+ *
+ * suggested on the forums...
+ *------------------------------------------
+ */
+
+int buildin_gmcommand(struct script_state *st)
+{
+ struct map_session_data *sd;
+ char *cmd;
+
+ sd = script_rid2sd(st);
+ cmd = conv_str(st,& (st->stack->stack_data[st->start+2]));
+
+ is_atcommand(sd->fd, sd, cmd, 99);
+
+ return 0;
+}
+
+/*==========================================
+ * movenpc [MouseJstr]
+ *------------------------------------------
+ */
+
+int buildin_movenpc(struct script_state *st)
+{
+ struct map_session_data *sd;
+ char *map,*npc;
+ int x,y;
+
+ sd = script_rid2sd(st);
+
+ map = conv_str(st,& (st->stack->stack_data[st->start+2]));
+ x = conv_num(st,& (st->stack->stack_data[st->start+3]));
+ y = conv_num(st,& (st->stack->stack_data[st->start+4]));
+ npc = conv_str(st,& (st->stack->stack_data[st->start+5]));
+
+ return 0;
+}
+
+/*==========================================
+ * message [MouseJstr]
+ *------------------------------------------
+ */
+
+int buildin_message(struct script_state *st)
+{
+ struct map_session_data *sd;
+ char *msg,*player;
+ struct map_session_data *pl_sd = NULL;
+
+ sd = script_rid2sd(st);
+
+ player = conv_str(st,& (st->stack->stack_data[st->start+2]));
+ msg = conv_str(st,& (st->stack->stack_data[st->start+3]));
+
+ if((pl_sd=map_nick2sd((char *) player)) == NULL)
+ return 1;
+ clif_displaymessage(pl_sd->fd, msg);
+
+ return 0;
+}
+
+/*==========================================
+ * npctalk (sends message to surrounding
+ * area) [Valaris]
+ *------------------------------------------
+ */
+
+int buildin_npctalk(struct script_state *st)
+{
+ char *str;
+ char message[255];
+
+ struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
+ str=conv_str(st,& (st->stack->stack_data[st->start+2]));
+
+ if(nd) {
+ memcpy(message,nd->name,24);
+ strcat(message," : ");
+ strcat(message,str);
+ clif_message(&(nd->bl), message);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * hasitems (checks to see if player has any
+ * items on them, if so will return a 1)
+ * [Valaris]
+ *------------------------------------------
+ */
+
+int buildin_hasitems(struct script_state *st)
+{
+ int i;
+ struct map_session_data *sd;
+
+ sd=script_rid2sd(st);
+
+ for(i=0; i<MAX_INVENTORY; i++) {
+ if(sd->status.inventory[i].amount) {
+ push_val(st->stack,C_INT,1);
+ return 0;
+ }
+ }
+
+ push_val(st->stack,C_INT,0);
+
+ return 0;
+}
+// change npc walkspeed [Valaris]
+int buildin_npcspeed(struct script_state *st)
+{
+ struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
+ int x=0;
+
+ x=conv_num(st,& (st->stack->stack_data[st->start+2]));
+
+ if(nd) {
+ nd->speed=x;
+ }
+
+ return 0;
+}
+// make an npc walk to a position [Valaris]
+int buildin_npcwalkto(struct script_state *st)
+{
+ struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
+ int x=0,y=0;
+
+ x=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ y=conv_num(st,& (st->stack->stack_data[st->start+3]));
+
+ if(nd) {
+ npc_walktoxy(nd,x,y,0);
+ }
+
+ return 0;
+}
+// stop an npc's movement [Valaris]
+int buildin_npcstop(struct script_state *st)
+{
+ struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
+
+ if(nd) {
+ if(nd->state.state==MS_WALK)
+ npc_stop_walking(nd,1);
+ }
+
+ return 0;
+}
+
+
+/*==========================================
+ * getlook char info. getlook(arg)
+ *------------------------------------------
+ */
+int buildin_getlook(struct script_state *st){
+ int type,val;
+ struct map_session_data *sd;
+ sd=script_rid2sd(st);
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ val=-1;
+ switch(type){
+ case LOOK_HAIR: //1
+ val=sd->status.hair;
+ break;
+ case LOOK_WEAPON: //2
+ val=sd->status.weapon;
+ break;
+ case LOOK_HEAD_BOTTOM: //3
+ val=sd->status.head_bottom;
+ break;
+ case LOOK_HEAD_TOP: //4
+ val=sd->status.head_top;
+ break;
+ case LOOK_HEAD_MID: //5
+ val=sd->status.head_mid;
+ break;
+ case LOOK_HAIR_COLOR: //6
+ val=sd->status.hair_color;
+ break;
+ case LOOK_CLOTHES_COLOR: //7
+ val=sd->status.clothes_color;
+ break;
+ case LOOK_SHIELD: //8
+ val=sd->status.shield;
+ break;
+ case LOOK_SHOES: //9
+ break;
+ }
+
+ push_val(st->stack,C_INT,val);
+ return 0;
+}
+
+/*==========================================
+ * get char save point. argument: 0- map name, 1- x, 2- y
+ *------------------------------------------
+*/
+int buildin_getsavepoint(struct script_state *st)
+{
+ int x,y,type;
+ char *mapname;
+ struct map_session_data *sd;
+
+ sd=script_rid2sd(st);
+
+ type=conv_num(st,& (st->stack->stack_data[st->start+2]));
+ mapname=calloc(24, 1);
+
+ x=sd->status.save_point.x;
+ y=sd->status.save_point.y;
+ strncpy(mapname,sd->status.save_point.map,24);
+ switch(type){
+ case 0:
+ push_str(st->stack,C_STR,mapname);
+ break;
+ case 1:
+ push_val(st->stack,C_INT,x);
+ break;
+ case 2:
+ push_val(st->stack,C_INT,y);
+ break;
+ }
+ return 0;
+}
+
+
+//
+// 実行部main
+//
+/*==========================================
+ * コマンドの読み取り
+ *------------------------------------------
+ */
+static int unget_com_data=-1;
+int get_com(unsigned char *script,int *pos)
+{
+ int i,j;
+ if(unget_com_data>=0){
+ i=unget_com_data;
+ unget_com_data=-1;
+ return i;
+ }
+ if(script[*pos]>=0x80){
+ return C_INT;
+ }
+ i=0; j=0;
+ while(script[*pos]>=0x40){
+ i=script[(*pos)++]<<j;
+ j+=6;
+ }
+ return i+(script[(*pos)++]<<j);
+}
+
+/*==========================================
+ * コマンドのプッシュバック
+ *------------------------------------------
+ */
+void unget_com(int c)
+{
+ if(unget_com_data!=-1){
+ if(battle_config.error_log)
+ printf("unget_com can back only 1 data\n");
+ }
+ unget_com_data=c;
+}
+
+/*==========================================
+ * 数値の所得
+ *------------------------------------------
+ */
+int get_num(unsigned char *script,int *pos)
+{
+ int i,j;
+ i=0; j=0;
+ while(script[*pos]>=0xc0){
+ i+=(script[(*pos)++]&0x7f)<<j;
+ j+=6;
+ }
+ return i+((script[(*pos)++]&0x7f)<<j);
+}
+
+/*==========================================
+ * スタックから値を取り出す
+ *------------------------------------------
+ */
+int pop_val(struct script_state* st)
+{
+ if(st->stack->sp<=0)
+ return 0;
+ st->stack->sp--;
+ get_val(st,&(st->stack->stack_data[st->stack->sp]));
+ if(st->stack->stack_data[st->stack->sp].type==C_INT)
+ return st->stack->stack_data[st->stack->sp].u.num;
+ return 0;
+}
+
+#define isstr(c) ((c).type==C_STR || (c).type==C_CONSTSTR)
+
+/*==========================================
+ * 加算演算子
+ *------------------------------------------
+ */
+void op_add(struct script_state* st)
+{
+ st->stack->sp--;
+ get_val(st,&(st->stack->stack_data[st->stack->sp]));
+ get_val(st,&(st->stack->stack_data[st->stack->sp-1]));
+
+ if(isstr(st->stack->stack_data[st->stack->sp]) || isstr(st->stack->stack_data[st->stack->sp-1])){
+ conv_str(st,&(st->stack->stack_data[st->stack->sp]));
+ conv_str(st,&(st->stack->stack_data[st->stack->sp-1]));
+ }
+ if(st->stack->stack_data[st->stack->sp].type==C_INT){ // ii
+ st->stack->stack_data[st->stack->sp-1].u.num += st->stack->stack_data[st->stack->sp].u.num;
+ } else { // ssの予定
+ char *buf;
+ buf=(char *)aCalloc(strlen(st->stack->stack_data[st->stack->sp-1].u.str)+
+ strlen(st->stack->stack_data[st->stack->sp].u.str)+1,sizeof(char));
+ strcpy(buf,st->stack->stack_data[st->stack->sp-1].u.str);
+ strcat(buf,st->stack->stack_data[st->stack->sp].u.str);
+ if(st->stack->stack_data[st->stack->sp-1].type==C_STR)
+ free(st->stack->stack_data[st->stack->sp-1].u.str);
+ if(st->stack->stack_data[st->stack->sp].type==C_STR)
+ free(st->stack->stack_data[st->stack->sp].u.str);
+ st->stack->stack_data[st->stack->sp-1].type=C_STR;
+ st->stack->stack_data[st->stack->sp-1].u.str=buf;
+ }
+}
+
+/*==========================================
+ * 二項演算子(文字列)
+ *------------------------------------------
+ */
+void op_2str(struct script_state *st,int op,int sp1,int sp2)
+{
+ char *s1=st->stack->stack_data[sp1].u.str,
+ *s2=st->stack->stack_data[sp2].u.str;
+ int a=0;
+
+ switch(op){
+ case C_EQ:
+ a= (strcmp(s1,s2)==0);
+ break;
+ case C_NE:
+ a= (strcmp(s1,s2)!=0);
+ break;
+ case C_GT:
+ a= (strcmp(s1,s2)> 0);
+ break;
+ case C_GE:
+ a= (strcmp(s1,s2)>=0);
+ break;
+ case C_LT:
+ a= (strcmp(s1,s2)< 0);
+ break;
+ case C_LE:
+ a= (strcmp(s1,s2)<=0);
+ break;
+ default:
+ printf("illegal string operater\n");
+ break;
+ }
+
+ push_val(st->stack,C_INT,a);
+
+ if(st->stack->stack_data[sp1].type==C_STR) free(s1);
+ if(st->stack->stack_data[sp2].type==C_STR) free(s2);
+}
+/*==========================================
+ * 二項演算子(数値)
+ *------------------------------------------
+ */
+void op_2num(struct script_state *st,int op,int i1,int i2)
+{
+ switch(op){
+ case C_SUB:
+ i1-=i2;
+ break;
+ case C_MUL:
+ {
+ long long res = i1 * i2;
+ if (res > 2147483647 )
+ i1 = 2147483647;
+ else
+ i1*=i2;
+ }
+ break;
+ case C_DIV:
+ i1/=i2;
+ break;
+ case C_MOD:
+ i1%=i2;
+ break;
+ case C_AND:
+ i1&=i2;
+ break;
+ case C_OR:
+ i1|=i2;
+ break;
+ case C_XOR:
+ i1^=i2;
+ break;
+ case C_LAND:
+ i1=i1&&i2;
+ break;
+ case C_LOR:
+ i1=i1||i2;
+ break;
+ case C_EQ:
+ i1=i1==i2;
+ break;
+ case C_NE:
+ i1=i1!=i2;
+ break;
+ case C_GT:
+ i1=i1>i2;
+ break;
+ case C_GE:
+ i1=i1>=i2;
+ break;
+ case C_LT:
+ i1=i1<i2;
+ break;
+ case C_LE:
+ i1=i1<=i2;
+ break;
+ case C_R_SHIFT:
+ i1=i1>>i2;
+ break;
+ case C_L_SHIFT:
+ i1=i1<<i2;
+ break;
+ }
+ push_val(st->stack,C_INT,i1);
+}
+/*==========================================
+ * 二項演算子
+ *------------------------------------------
+ */
+void op_2(struct script_state *st,int op)
+{
+ int i1,i2;
+ char *s1=NULL,*s2=NULL;
+
+ i2=pop_val(st);
+ if( isstr(st->stack->stack_data[st->stack->sp]) )
+ s2=st->stack->stack_data[st->stack->sp].u.str;
+
+ i1=pop_val(st);
+ if( isstr(st->stack->stack_data[st->stack->sp]) )
+ s1=st->stack->stack_data[st->stack->sp].u.str;
+
+ if( s1!=NULL && s2!=NULL ){
+ // ss => op_2str
+ op_2str(st,op,st->stack->sp,st->stack->sp+1);
+ }else if( s1==NULL && s2==NULL ){
+ // ii => op_2num
+ op_2num(st,op,i1,i2);
+ }else{
+ // si,is => error
+ printf("script: op_2: int&str, str&int not allow.");
+ push_val(st->stack,C_INT,0);
+ }
+}
+
+/*==========================================
+ * 単項演算子
+ *------------------------------------------
+ */
+void op_1num(struct script_state *st,int op)
+{
+ int i1;
+ i1=pop_val(st);
+ switch(op){
+ case C_NEG:
+ i1=-i1;
+ break;
+ case C_NOT:
+ i1=~i1;
+ break;
+ case C_LNOT:
+ i1=!i1;
+ break;
+ }
+ push_val(st->stack,C_INT,i1);
+}
+
+
+/*==========================================
+ * 関数の実行
+ *------------------------------------------
+ */
+int run_func(struct script_state *st)
+{
+ int i,start_sp,end_sp,func;
+
+ end_sp=st->stack->sp;
+ for(i=end_sp-1;i>=0 && st->stack->stack_data[i].type!=C_ARG;i--);
+ if(i==0){
+ if(battle_config.error_log)
+ printf("function not found\n");
+// st->stack->sp=0;
+ st->state=END;
+ return 0;
+ }
+ start_sp=i-1;
+ st->start=i-1;
+ st->end=end_sp;
+
+ func=st->stack->stack_data[st->start].u.num;
+ if( st->stack->stack_data[st->start].type!=C_NAME || str_data[func].type!=C_FUNC ){
+ printf("run_func: not function and command! \n");
+// st->stack->sp=0;
+ st->state=END;
+ return 0;
+ }
+#ifdef DEBUG_RUN
+ if(battle_config.etc_log) {
+ printf("run_func : %s? (%d(%d))\n",str_buf+str_data[func].str,func,str_data[func].type);
+ printf("stack dump :");
+ for(i=0;i<end_sp;i++){
+ switch(st->stack->stack_data[i].type){
+ case C_INT:
+ printf(" int(%d)",st->stack->stack_data[i].u.num);
+ break;
+ case C_NAME:
+ printf(" name(%s)",str_buf+str_data[st->stack->stack_data[i].u.num].str);
+ break;
+ case C_ARG:
+ printf(" arg");
+ break;
+ case C_POS:
+ printf(" pos(%d)",st->stack->stack_data[i].u.num);
+ break;
+ default:
+ printf(" %d,%d",st->stack->stack_data[i].type,st->stack->stack_data[i].u.num);
+ }
+ }
+ printf("\n");
+ }
+#endif
+ if(str_data[func].func){
+ str_data[func].func(st);
+ } else {
+ if(battle_config.error_log)
+ printf("run_func : %s? (%d(%d))\n",str_buf+str_data[func].str,func,str_data[func].type);
+ push_val(st->stack,C_INT,0);
+ }
+
+ pop_stack(st->stack,start_sp,end_sp);
+
+ if(st->state==RETFUNC){
+ // ユーザー定義関数からの復帰
+ int olddefsp=st->defsp;
+ int i;
+
+ pop_stack(st->stack,st->defsp,start_sp); // 復帰に邪魔なスタック削除
+ if(st->defsp<4 || st->stack->stack_data[st->defsp-1].type!=C_RETINFO){
+ printf("script:run_func(return) return without callfunc or callsub!\n");
+ st->state=END;
+ return 0;
+ }
+ i = conv_num(st,& (st->stack->stack_data[st->defsp-4])); // 引数の数所得
+ st->pos=conv_num(st,& (st->stack->stack_data[st->defsp-1])); // スクリプト位置の復元
+ st->script=(char*)conv_num(st,& (st->stack->stack_data[st->defsp-2])); // スクリプトを復元
+ st->defsp=conv_num(st,& (st->stack->stack_data[st->defsp-3])); // 基準スタックポインタを復元
+
+ pop_stack(st->stack,olddefsp-4-i,olddefsp); // 要らなくなったスタック(引数と復帰用データ)削除
+
+ st->state=GOTO;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * スクリプトの実行メイン部分
+ *------------------------------------------
+ */
+int run_script_main(unsigned char *script,int pos,int rid,int oid,struct script_state *st,unsigned char *rootscript)
+{
+ int c,rerun_pos;
+ int cmdcount=script_config.check_cmdcount;
+ int gotocount=script_config.check_gotocount;
+ struct script_stack *stack=st->stack;
+
+ st->defsp=stack->sp;
+ st->script=script;
+
+ rerun_pos=st->pos;
+ for(st->state=0;st->state==0;){
+ switch(c=get_com(script,&st->pos)){
+ case C_EOL:
+ if(stack->sp!=st->defsp){
+ if(battle_config.error_log)
+ printf("stack.sp(%d) != default(%d)\n",stack->sp,st->defsp);
+ stack->sp=st->defsp;
+ }
+ rerun_pos=st->pos;
+ break;
+ case C_INT:
+ push_val(stack,C_INT,get_num(script,&st->pos));
+ break;
+ case C_POS:
+ case C_NAME:
+ push_val(stack,c,(*(int*)(script+st->pos))&0xffffff);
+ st->pos+=3;
+ break;
+ case C_ARG:
+ push_val(stack,c,0);
+ break;
+ case C_STR:
+ push_str(stack,C_CONSTSTR,script+st->pos);
+ while(script[st->pos++]);
+ break;
+ case C_FUNC:
+ run_func(st);
+ if(st->state==GOTO){
+ rerun_pos=st->pos;
+ script=st->script;
+ st->state=0;
+ if( gotocount>0 && (--gotocount)<=0 ){
+ printf("run_script: infinity loop !\n");
+ st->state=END;
+ }
+ }
+ break;
+
+ case C_ADD:
+ op_add(st);
+ break;
+
+ case C_SUB:
+ case C_MUL:
+ case C_DIV:
+ case C_MOD:
+ case C_EQ:
+ case C_NE:
+ case C_GT:
+ case C_GE:
+ case C_LT:
+ case C_LE:
+ case C_AND:
+ case C_OR:
+ case C_XOR:
+ case C_LAND:
+ case C_LOR:
+ case C_R_SHIFT:
+ case C_L_SHIFT:
+ op_2(st,c);
+ break;
+
+ case C_NEG:
+ case C_NOT:
+ case C_LNOT:
+ op_1num(st,c);
+ break;
+
+ case C_NOP:
+ st->state=END;
+ break;
+
+ default:
+ if(battle_config.error_log)
+ printf("unknown command : %d @ %d\n",c,pos);
+ st->state=END;
+ break;
+ }
+ if( cmdcount>0 && (--cmdcount)<=0 ){
+ printf("run_script: infinity loop !\n");
+ st->state=END;
+ }
+ }
+ switch(st->state){
+ case STOP:
+ break;
+ case END:
+ {
+ struct map_session_data *sd=map_id2sd(st->rid);
+ st->pos=-1;
+ if(sd && sd->npc_id==st->oid)
+ npc_event_dequeue(sd);
+ }
+ break;
+ case RERUNLINE:
+ {
+ st->pos=rerun_pos;
+ }
+ break;
+ }
+
+ if( st->state!=END){
+ // 再開するためにスタック情報を保存
+ struct map_session_data *sd=map_id2sd(st->rid);
+ if(sd/* && sd->npc_stackbuf==NULL*/){
+ if( sd->npc_stackbuf )
+ free( sd->npc_stackbuf );
+ sd->npc_stackbuf = (char *)aCalloc(sizeof(stack->stack_data[0])*stack->sp_max,sizeof(char));
+ memcpy(sd->npc_stackbuf, stack->stack_data, sizeof(stack->stack_data[0]) * stack->sp_max);
+ sd->npc_stack = stack->sp;
+ sd->npc_stackmax = stack->sp_max;
+ sd->npc_script=script;
+ sd->npc_scriptroot=rootscript;
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * スクリプトの実行
+ *------------------------------------------
+ */
+int run_script(unsigned char *script,int pos,int rid,int oid)
+{
+ struct script_stack stack;
+ struct script_state st;
+ struct map_session_data *sd=map_id2sd(rid);
+ unsigned char *rootscript=script;
+
+ if(script==NULL || pos<0)
+ return -1;
+
+ if(sd && sd->npc_stackbuf && sd->npc_scriptroot==(char*)rootscript){
+ // 前回のスタックを復帰
+ script=sd->npc_script;
+ stack.sp=sd->npc_stack;
+ stack.sp_max=sd->npc_stackmax;
+ stack.stack_data=(struct script_data *)aCalloc(stack.sp_max,sizeof(stack.stack_data[0]));
+ memcpy(stack.stack_data,sd->npc_stackbuf,sizeof(stack.stack_data[0])*stack.sp_max);
+ free(sd->npc_stackbuf);
+ sd->npc_stackbuf=NULL;
+ }else{
+ // スタック初期化
+ stack.sp=0;
+ stack.sp_max=64;
+ stack.stack_data=(struct script_data *)aCalloc(stack.sp_max,sizeof(stack.stack_data[0]));
+ }
+ st.stack=&stack;
+ st.pos=pos;
+ st.rid=rid;
+ st.oid=oid;
+ run_script_main(script,pos,rid,oid,&st,rootscript);
+
+ free(stack.stack_data);
+ stack.stack_data=NULL;
+ return st.pos;
+}
+
+
+/*==========================================
+ * マップ変数の変更
+ *------------------------------------------
+ */
+int mapreg_setreg(int num,int val)
+{
+ if(val!=0)
+ numdb_insert(mapreg_db,num,val);
+ else
+ numdb_erase(mapreg_db,num);
+
+ mapreg_dirty=1;
+ return 0;
+}
+/*==========================================
+ * 文字列型マップ変数の変更
+ *------------------------------------------
+ */
+int mapreg_setregstr(int num,const char *str)
+{
+ char *p;
+
+ if( (p=numdb_search(mapregstr_db,num))!=NULL )
+ free(p);
+
+ if( str==NULL || *str==0 ){
+ numdb_erase(mapregstr_db,num);
+ mapreg_dirty=1;
+ return 0;
+ }
+ p=(char *)aCalloc(strlen(str)+1, sizeof(char));
+ strcpy(p,str);
+ numdb_insert(mapregstr_db,num,p);
+ mapreg_dirty=1;
+ return 0;
+}
+
+/*==========================================
+ * 永続的マップ変数の読み込み
+ *------------------------------------------
+ */
+static int script_load_mapreg()
+{
+ FILE *fp;
+ char line[1024];
+
+ if( (fp=fopen(mapreg_txt,"rt"))==NULL )
+ return -1;
+
+ while(fgets(line,sizeof(line),fp)){
+ char buf1[256],buf2[1024],*p;
+ int n,v,s,i;
+ if( sscanf(line,"%255[^,],%d\t%n",buf1,&i,&n)!=2 &&
+ (i=0,sscanf(line,"%[^\t]\t%n",buf1,&n)!=1) )
+ continue;
+ if( buf1[strlen(buf1)-1]=='$' ){
+ if( sscanf(line+n,"%[^\n\r]",buf2)!=1 ){
+ printf("%s: %s broken data !\n",mapreg_txt,buf1);
+ continue;
+ }
+ p=(char *)aCalloc(strlen(buf2) + 1,sizeof(char));
+ strcpy(p,buf2);
+ s=add_str(buf1);
+ numdb_insert(mapregstr_db,(i<<24)|s,p);
+ }else{
+ if( sscanf(line+n,"%d",&v)!=1 ){
+ printf("%s: %s broken data !\n",mapreg_txt,buf1);
+ continue;
+ }
+ s=add_str(buf1);
+ numdb_insert(mapreg_db,(i<<24)|s,v);
+ }
+ }
+ fclose(fp);
+ mapreg_dirty=0;
+ return 0;
+}
+/*==========================================
+ * 永続的マップ変数の書き込み
+ *------------------------------------------
+ */
+static int script_save_mapreg_intsub(void *key,void *data,va_list ap)
+{
+ FILE *fp=va_arg(ap,FILE*);
+ int num=((int)key)&0x00ffffff, i=((int)key)>>24;
+ char *name=str_buf+str_data[num].str;
+ if( name[1]!='@' ){
+ if(i==0)
+ fprintf(fp,"%s\t%d\n", name, (int)data);
+ else
+ fprintf(fp,"%s,%d\t%d\n", name, i, (int)data);
+ }
+ return 0;
+}
+static int script_save_mapreg_strsub(void *key,void *data,va_list ap)
+{
+ FILE *fp=va_arg(ap,FILE*);
+ int num=((int)key)&0x00ffffff, i=((int)key)>>24;
+ char *name=str_buf+str_data[num].str;
+ if( name[1]!='@' ){
+ if(i==0)
+ fprintf(fp,"%s\t%s\n", name, (char *)data);
+ else
+ fprintf(fp,"%s,%d\t%s\n", name, i, (char *)data);
+ }
+ return 0;
+}
+static int script_save_mapreg()
+{
+ FILE *fp;
+ int lock;
+
+ if( (fp=lock_fopen(mapreg_txt,&lock))==NULL )
+ return -1;
+ numdb_foreach(mapreg_db,script_save_mapreg_intsub,fp);
+ numdb_foreach(mapregstr_db,script_save_mapreg_strsub,fp);
+ lock_fclose(fp,mapreg_txt,&lock);
+ mapreg_dirty=0;
+ return 0;
+}
+static int script_autosave_mapreg(int tid,unsigned int tick,int id,int data)
+{
+ if(mapreg_dirty)
+ script_save_mapreg();
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static int set_posword(char *p)
+{
+ char* np,* str[15];
+ int i=0;
+ for(i=0;i<11;i++) {
+ if((np=strchr(p,','))!=NULL) {
+ str[i]=p;
+ *np=0;
+ p=np+1;
+ } else {
+ str[i]=p;
+ p+=strlen(p);
+ }
+ if(str[i])
+ strcpy(pos[i],str[i]);
+ }
+ return 0;
+}
+
+int script_config_read(char *cfgName)
+{
+ int i;
+ char line[1024],w1[1024],w2[1024];
+ FILE *fp;
+
+ script_config.warn_func_no_comma=1;
+ script_config.warn_cmd_no_comma=1;
+ script_config.warn_func_mismatch_paramnum=1;
+ script_config.warn_cmd_mismatch_paramnum=1;
+ script_config.check_cmdcount=8192;
+ script_config.check_gotocount=512;
+
+ fp=fopen(cfgName,"r");
+ if(fp==NULL){
+ printf("file not found: %s\n",cfgName);
+ return 1;
+ }
+ while(fgets(line,1020,fp)){
+ if(line[0] == '/' && line[1] == '/')
+ continue;
+ i=sscanf(line,"%[^:]: %[^\r\n]",w1,w2);
+ if(i!=2)
+ continue;
+ if(strcmpi(w1,"refine_posword")==0) {
+ set_posword(w2);
+ }
+ if(strcmpi(w1,"import")==0){
+ script_config_read(w2);
+ }
+ }
+ fclose(fp);
+
+ return 0;
+}
+
+/*==========================================
+ * 終了
+ *------------------------------------------
+ */
+static int mapreg_db_final(void *key,void *data,va_list ap)
+{
+ return 0;
+}
+static int mapregstr_db_final(void *key,void *data,va_list ap)
+{
+ free(data);
+ return 0;
+}
+static int scriptlabel_db_final(void *key,void *data,va_list ap)
+{
+ return 0;
+}
+static int userfunc_db_final(void *key,void *data,va_list ap)
+{
+ free(key);
+ free(data);
+ return 0;
+}
+int do_final_script()
+{
+ if(mapreg_dirty>=0)
+ script_save_mapreg();
+ if(script_buf)
+ free(script_buf);
+
+ if(mapreg_db)
+ numdb_final(mapreg_db,mapreg_db_final);
+ if(mapregstr_db)
+ strdb_final(mapregstr_db,mapregstr_db_final);
+ if(scriptlabel_db)
+ strdb_final(scriptlabel_db,scriptlabel_db_final);
+ if(userfunc_db)
+ strdb_final(userfunc_db,userfunc_db_final);
+
+ if (str_data)
+ free(str_data);
+ if (str_buf)
+ free(str_buf);
+
+ return 0;
+}
+/*==========================================
+ * 初期化
+ *------------------------------------------
+ */
+int do_init_script()
+{
+ mapreg_db=numdb_init();
+ mapregstr_db=numdb_init();
+ script_load_mapreg();
+
+ add_timer_func_list(script_autosave_mapreg,"script_autosave_mapreg");
+ add_timer_interval(gettick()+MAPREG_AUTOSAVE_INTERVAL,
+ script_autosave_mapreg,0,0,MAPREG_AUTOSAVE_INTERVAL);
+
+ scriptlabel_db=strdb_init(50);
+ return 0;
+}
diff --git a/src/map/script.h b/src/map/script.h
new file mode 100644
index 000000000..c0c4ba20f
--- /dev/null
+++ b/src/map/script.h
@@ -0,0 +1,39 @@
+// $Id: script.h,v 1.2 2004/09/25 05:32:19 MouseJstr Exp $
+#ifndef _SCRIPT_H_
+#define _SCRIPT_H_
+
+struct script_data {
+ int type;
+ union {
+ int num;
+ char *str;
+ } u;
+};
+
+struct script_stack {
+ int sp,sp_max;
+ struct script_data *stack_data;
+};
+struct script_state {
+ struct script_stack *stack;
+ int start,end;
+ int pos,state;
+ int rid,oid;
+ char *script,*new_script;
+ int defsp,new_pos,new_defsp;
+};
+
+unsigned char * parse_script(unsigned char *,int);
+int run_script(unsigned char *,int,int,int);
+
+struct dbt* script_get_label_db();
+struct dbt* script_get_userfunc_db();
+
+int script_config_read(char *cfgName);
+int do_init_script();
+int do_final_script();
+
+extern char mapreg_txt[];
+
+#endif
+
diff --git a/src/map/skill.c b/src/map/skill.c
new file mode 100644
index 000000000..de4ce3624
--- /dev/null
+++ b/src/map/skill.c
@@ -0,0 +1,10682 @@
+// $Id: skill.c,v 1.8 2004/09/25 05:32:19 MouseJstr Exp $
+/* スキル関係 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "timer.h"
+#include "nullpo.h"
+#include "malloc.h"
+
+#include "skill.h"
+#include "map.h"
+#include "clif.h"
+#include "pc.h"
+#include "pet.h"
+#include "mob.h"
+#include "battle.h"
+#include "party.h"
+#include "itemdb.h"
+#include "script.h"
+#include "intif.h"
+#include "log.h"
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+#define SKILLUNITTIMER_INVERVAL 100
+
+#define STATE_BLIND 0x10
+
+/* スキル番号=>ステータス異常番号変換テーブル */
+int SkillStatusChangeTable[]={ /* skill.hのenumのSC_***とあわせること */
+/* 0- */
+ -1,-1,-1,-1,-1,-1,
+ SC_PROVOKE, /* プロボック */
+ -1, 1,-1,
+/* 10- */
+ SC_SIGHT, /* サイト */
+ -1,-1,-1,-1,
+ SC_FREEZE, /* フロストダイバー */
+ SC_STONE, /* ストーンカース */
+ -1,-1,-1,
+/* 20- */
+ -1,-1,-1,-1,
+ SC_RUWACH, /* ルアフ */
+ -1,-1,-1,-1,
+ SC_INCREASEAGI, /* 速度増加 */
+/* 30- */
+ SC_DECREASEAGI, /* 速度減少 */
+ -1,
+ SC_SIGNUMCRUCIS, /* シグナムクルシス */
+ SC_ANGELUS, /* エンジェラス */
+ SC_BLESSING, /* ブレッシング */
+ -1,-1,-1,-1,-1,
+/* 40- */
+ -1,-1,-1,-1,-1,
+ SC_CONCENTRATE, /* 集中力向上 */
+ -1,-1,-1,-1,
+/* 50- */
+ -1,
+ SC_HIDING, /* ハイディング */
+ -1,-1,-1,-1,-1,-1,-1,-1,
+/* 60- */
+ SC_TWOHANDQUICKEN, /* 2HQ */
+ SC_AUTOCOUNTER,
+ -1,-1,-1,-1,
+ SC_IMPOSITIO, /* インポシティオマヌス */
+ SC_SUFFRAGIUM, /* サフラギウム */
+ SC_ASPERSIO, /* アスペルシオ */
+ SC_BENEDICTIO, /* 聖体降福 */
+/* 70- */
+ -1,
+ SC_SLOWPOISON,
+ -1,
+ SC_KYRIE, /* キリエエレイソン */
+ SC_MAGNIFICAT, /* マグニフィカート */
+ SC_GLORIA, /* グロリア */
+ SC_DIVINA, /* レックスディビーナ */
+ -1,
+ SC_AETERNA, /* レックスエーテルナ */
+ -1,
+/* 80- */
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+/* 90- */
+ -1,-1,
+ SC_QUAGMIRE, /* クァグマイア */
+ -1,-1,-1,-1,-1,-1,-1,
+/* 100- */
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+/* 110- */
+ -1,
+ SC_ADRENALINE, /* アドレナリンラッシュ */
+ SC_WEAPONPERFECTION,/* ウェポンパーフェクション */
+ SC_OVERTHRUST, /* オーバートラスト */
+ SC_MAXIMIZEPOWER, /* マキシマイズパワー */
+ -1,-1,-1,-1,-1,
+/* 120- */
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+/* 130- */
+ -1,-1,-1,-1,-1,
+ SC_CLOAKING, /* クローキング */
+ SC_STAN, /* ソニックブロー */
+ -1,
+ SC_ENCPOISON, /* エンチャントポイズン */
+ SC_POISONREACT, /* ポイズンリアクト */
+/* 140- */
+ SC_POISON, /* ベノムダスト */
+ SC_SPLASHER, /* ベナムスプラッシャー */
+ -1,
+ SC_TRICKDEAD, /* 死んだふり */
+ -1,-1,-1,-1,-1,-1,
+/* 150- */
+ -1,-1,-1,-1,-1,
+ SC_LOUD, /* ラウドボイス */
+ -1,
+ SC_ENERGYCOAT, /* エナジーコート */
+ -1,-1,
+/* 160- */
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,
+ SC_SELFDESTRUCTION,
+ -1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,
+ SC_KEEPING,
+ -1,-1,
+ SC_BARRIER,
+ -1,-1,
+ SC_HALLUCINATION,
+ -1,-1,
+/* 210- */
+ -1,-1,-1,-1,-1,
+ SC_STRIPWEAPON,
+ SC_STRIPSHIELD,
+ SC_STRIPARMOR,
+ SC_STRIPHELM,
+ -1,
+/* 220- */
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+/* 230- */
+ -1,-1,-1,-1,
+ SC_CP_WEAPON,
+ SC_CP_SHIELD,
+ SC_CP_ARMOR,
+ SC_CP_HELM,
+ -1,-1,
+/* 240- */
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,
+ SC_AUTOGUARD,
+/* 250- */
+ -1,-1,
+ SC_REFLECTSHIELD,
+ -1,-1,
+ SC_DEVOTION,
+ SC_PROVIDENCE,
+ SC_DEFENDER,
+ SC_SPEARSQUICKEN,
+ -1,
+/* 260- */
+ -1,-1,-1,-1,-1,-1,-1,-1,
+ SC_STEELBODY,
+ SC_BLADESTOP_WAIT,
+/* 270- */
+ SC_EXPLOSIONSPIRITS,
+ SC_EXTREMITYFIST,
+ -1,-1,-1,-1,
+ SC_MAGICROD,
+ -1,-1,-1,
+/* 280- */
+ SC_FLAMELAUNCHER,
+ SC_FROSTWEAPON,
+ SC_LIGHTNINGLOADER,
+ SC_SEISMICWEAPON,
+ -1,
+ SC_VOLCANO,
+ SC_DELUGE,
+ SC_VIOLENTGALE,
+ SC_LANDPROTECTOR,
+ -1,
+/* 290- */
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+/* 300- */
+ -1,-1,-1,-1,-1,-1,
+ SC_LULLABY,
+ SC_RICHMANKIM,
+ SC_ETERNALCHAOS,
+ SC_DRUMBATTLE,
+/* 310- */
+ SC_NIBELUNGEN,
+ SC_ROKISWEIL,
+ SC_INTOABYSS,
+ SC_SIEGFRIED,
+ -1,-1,-1,
+ SC_DISSONANCE,
+ -1,
+ SC_WHISTLE,
+/* 320- */
+ SC_ASSNCROS,
+ SC_POEMBRAGI,
+ SC_APPLEIDUN,
+ -1,-1,
+ SC_UGLYDANCE,
+ -1,
+ SC_HUMMING,
+ SC_DONTFORGETME,
+ SC_FORTUNE,
+/* 330- */
+ SC_SERVICE4U,
+ SC_SELFDESTRUCTION,
+ -1,-1,-1,-1,-1,-1,-1,-1,
+/* 340- */
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+/* 350- */
+ -1,-1,-1,-1,-1,
+ SC_AURABLADE,
+ SC_PARRYING,
+ SC_CONCENTRATION,
+ SC_TENSIONRELAX,
+ SC_BERSERK,
+/* 360- */
+ SC_BERSERK,
+ SC_ASSUMPTIO,
+ SC_BASILICA,
+ -1,-1,-1,
+ SC_MAGICPOWER,
+ -1,-1,
+ SC_GOSPEL,
+/* 370- */
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+/* 380- */
+ SC_TRUESIGHT,
+ -1,-1,
+ SC_WINDWALK,
+ SC_MELTDOWN,
+ -1,-1,
+ SC_CARTBOOST,
+ -1,
+ SC_CHASEWALK,
+/* 390- */
+ SC_REJECTSWORD,
+ -1,-1,-1,-1,-1,
+ SC_MARIONETTE,
+ -1,
+ SC_HEADCRUSH,
+ SC_JOINTBEAT,
+/* 400 */
+ -1,-1,
+ SC_MINDBREAKER,
+ SC_MEMORIZE,
+ SC_FOGWALL,
+ SC_SPIDERWEB,
+ -1,-1,-1,-1,
+/* 410- */
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+};
+
+struct skill_name_db skill_names[] = {
+ { AC_CHARGEARROW, "CHARGEARROW", "Charge_Arrow" } ,
+ { AC_CONCENTRATION, "CONCENTRATION", "Improve_Concentration" } ,
+ { AC_DOUBLE, "DOUBLE", "Double_Strafe" } ,
+ { AC_MAKINGARROW, "MAKINGARROW", "Arrow_Creation" } ,
+ { AC_OWL, "OWL", "Owl's_Eye" } ,
+ { AC_SHOWER, "SHOWER", "Arrow_Shower" } ,
+ { AC_VULTURE, "VULTURE", "Vulture's_Eye" } ,
+ { ALL_RESURRECTION, "RESURRECTION", "Resurrection" } ,
+ { AL_ANGELUS, "ANGELUS", "Angelus" } ,
+ { AL_BLESSING, "BLESSING", "Blessing" } ,
+ { AL_CRUCIS, "CRUCIS", "Signum_Crusis" } ,
+ { AL_CURE, "CURE", "Cure" } ,
+ { AL_DECAGI, "DECAGI", "Decrease_AGI" } ,
+ { AL_DEMONBANE, "DEMONBANE", "Demon_Bane" } ,
+ { AL_DP, "DP", "Divine_Protection" } ,
+ { AL_HEAL, "HEAL", "Heal" } ,
+ { AL_HOLYLIGHT, "HOLYLIGHT", "Holy_Light" } ,
+ { AL_HOLYWATER, "HOLYWATER", "Aqua_Benedicta" } ,
+ { AL_INCAGI, "INCAGI", "Increase_AGI" } ,
+ { AL_PNEUMA, "PNEUMA", "Pneuma" } ,
+ { AL_RUWACH, "RUWACH", "Ruwach" } ,
+ { AL_TELEPORT, "TELEPORT", "Teleport" } ,
+ { AL_WARP, "WARP", "Warp_Portal" } ,
+ { AM_ACIDTERROR, "ACIDTERROR", "Acid_Terror" } ,
+ { AM_AXEMASTERY, "AXEMASTERY", "Axe_Mastery" } ,
+ { AM_BERSERKPITCHER, "BERSERKPITCHER", "Berserk Pitcher" } ,
+ { AM_BIOETHICS, "BIOETHICS", "Bioethics" } ,
+ { AM_BIOTECHNOLOGY, "BIOTECHNOLOGY", "Biotechnology" } ,
+ { AM_CALLHOMUN, "CALLHOMUN", "Call_Homunculus" } ,
+ { AM_CANNIBALIZE, "CANNIBALIZE", "Bio_Cannibalize" } ,
+ { AM_CP_ARMOR, "ARMOR", "Chemical_Protection_Armor" } ,
+ { AM_CP_HELM, "HELM", "Chemical_Protection_Helm" } ,
+ { AM_CP_SHIELD, "SHIELD", "Chemical_Protection_Shield" } ,
+ { AM_CP_WEAPON, "WEAPON", "Chemical_Protection_Weapon" } ,
+ { AM_CREATECREATURE, "CREATECREATURE", "Life_Creation" } ,
+ { AM_CULTIVATION, "CULTIVATION", "Cultivation" } ,
+ { AM_DEMONSTRATION, "DEMONSTRATION", "Demonstration" } ,
+ { AM_DRILLMASTER, "DRILLMASTER", "Drillmaster" } ,
+ { AM_FLAMECONTROL, "FLAMECONTROL", "Flame_Control" } ,
+ { AM_HEALHOMUN, "HEALHOMUN", "Heal_Homunculus" } ,
+ { AM_LEARNINGPOTION, "LEARNINGPOTION", "AM_LEARNINGPOTION" } ,
+ { AM_PHARMACY, "PHARMACY", "Pharmacy" } ,
+ { AM_POTIONPITCHER, "POTIONPITCHER", "Potion_Pitcher" } ,
+ { AM_REST, "REST", "Sabbath" } ,
+ { AM_RESURRECTHOMUN, "RESURRECTHOMUN", "Ressurect_Homunculus" } ,
+ { AM_SPHEREMINE, "SPHEREMINE", "Sphere_Mine" } ,
+ { ASC_BREAKER, "BREAKER", "Breaker" } ,
+ { ASC_CDP, "CDP", "Create_Deadly_Poison" } ,
+ { ASC_EDP, "EDP", "Deadly_Poison_Enchantment" } ,
+ { ASC_HALLUCINATION, "HALLUCINATION", "Hallucination_Walk" } ,
+ { ASC_KATAR, "KATAR", "Advanced_Katar_Mastery" } ,
+ { ASC_METEORASSAULT, "METEORASSAULT", "Meteor_Assault" } ,
+ { AS_CLOAKING, "CLOAKING", "Cloaking" } ,
+ { AS_ENCHANTPOISON, "ENCHANTPOISON", "Enchant_Poison" } ,
+ { AS_GRIMTOOTH, "GRIMTOOTH", "Grimtooth" } ,
+ { AS_KATAR, "KATAR", "Katar_Mastery" } ,
+ { AS_LEFT, "LEFT", "Lefthand_Mastery" } ,
+ { AS_POISONREACT, "POISONREACT", "Poison_React" } ,
+ { AS_RIGHT, "RIGHT", "Righthand_Mastery" } ,
+ { AS_SONICBLOW, "SONICBLOW", "Sonic_Blow" } ,
+ { AS_SPLASHER, "SPLASHER", "Venom_Splasher" } ,
+ { AS_VENOMDUST, "VENOMDUST", "Venom_Dust" } ,
+ { BA_APPLEIDUN, "APPLEIDUN", "Apple_of_Idun" } ,
+ { BA_ASSASSINCROSS, "ASSASSINCROSS", "Assassin_Cross" } ,
+ { BA_DISSONANCE, "DISSONANCE", "Dissonance" } ,
+ { BA_FROSTJOKE, "FROSTJOKE", "Dumb_Joke" } ,
+ { BA_MUSICALLESSON, "MUSICALLESSON", "Musical_Lesson" } ,
+ { BA_MUSICALSTRIKE, "MUSICALSTRIKE", "Musical_Strike" } ,
+ { BA_POEMBRAGI, "POEMBRAGI", "Poem_of_Bragi" } ,
+ { BA_WHISTLE, "WHISTLE", "Whistle" } ,
+ { BD_ADAPTATION, "ADAPTATION", "Adaption" } ,
+ { BD_DRUMBATTLEFIELD, "DRUMBATTLEFIELD", "Drumb_BattleField" } ,
+ { BD_ENCORE, "ENCORE", "Encore" } ,
+ { BD_ETERNALCHAOS, "ETERNALCHAOS", "Eternal_Chaos" } ,
+ { BD_INTOABYSS, "INTOABYSS", "Into_the_Abyss" } ,
+ { BD_LULLABY, "LULLABY", "Lullaby" } ,
+ { BD_RAGNAROK, "RAGNAROK", "Ragnarok" } ,
+ { BD_RICHMANKIM, "RICHMANKIM", "Rich_Mankim" } ,
+ { BD_RINGNIBELUNGEN, "RINGNIBELUNGEN", "Ring_of_Nibelugen" } ,
+ { BD_ROKISWEIL, "ROKISWEIL", "Loki's_Wail" } ,
+ { BD_SIEGFRIED, "SIEGFRIED", "Invulnerable_Siegfried" } ,
+ { BS_ADRENALINE, "ADRENALINE", "Adrenaline_Rush" } ,
+ { BS_ADRENALINE2, "ADRENALINE2", "Adrenaline Rush 2" } ,
+ { BS_AXE, "AXE", "Smith_Axe" } ,
+ { BS_DAGGER, "DAGGER", "Smith_Dagger" } ,
+ { BS_ENCHANTEDSTONE, "ENCHANTEDSTONE", "Enchantedstone_Craft" } ,
+ { BS_FINDINGORE, "FINDINGORE", "Ore_Discovery" } ,
+ { BS_HAMMERFALL, "HAMMERFALL", "Hammer_Fall" } ,
+ { BS_HILTBINDING, "HILTBINDING", "Hilt_Binding" } ,
+ { BS_IRON, "IRON", "Iron_Tempering" } ,
+ { BS_KNUCKLE, "KNUCKLE", "Smith_Knucklebrace" } ,
+ { BS_MACE, "MACE", "Smith_Mace" } ,
+ { BS_MAXIMIZE, "MAXIMIZE", "Power_Maximize" } ,
+ { BS_ORIDEOCON, "ORIDEOCON", "Orideocon_Research" } ,
+ { BS_OVERTHRUST, "OVERTHRUST", "Power-Thrust" } ,
+ { BS_REPAIRWEAPON, "REPAIRWEAPON", "Weapon_Repair" } ,
+ { BS_SKINTEMPER, "SKINTEMPER", "Skin_Tempering" } ,
+ { BS_SPEAR, "SPEAR", "Smith_Spear" } ,
+ { BS_STEEL, "STEEL", "Steel_Tempering" } ,
+ { BS_SWORD, "SWORD", "Smith_Sword" } ,
+ { BS_TWOHANDSWORD, "TWOHANDSWORD", "Smith_Two-handed_Sword" } ,
+ { BS_WEAPONPERFECT, "WEAPONPERFECT", "Weapon_Perfection" } ,
+ { BS_WEAPONRESEARCH, "WEAPONRESEARCH", "Weaponry_Research" } ,
+ { CG_ARROWVULCAN, "ARROWVULCAN", "Vulcan_Arrow" } ,
+ { CG_MARIONETTE, "MARIONETTE", "Marionette_Control" } ,
+ { CG_MOONLIT, "MOONLIT", "Moonlight_Petals" } ,
+ { CH_CHAINCRUSH, "CHAINCRUSH", "Chain_Crush_Combo" } ,
+ { CH_PALMSTRIKE, "PALMSTRIKE", "Palm_Push_Strike" } ,
+ { CH_SOULCOLLECT, "SOULCOLLECT", "Collect_Soul" } ,
+ { CH_TIGERFIST, "TIGERFIST", "Tiger_Knuckle_Fist" } ,
+ { CR_ALCHEMY, "ALCHEMY", "Alchemy" } ,
+ { CR_AUTOGUARD, "AUTOGUARD", "Guard" } ,
+ { CR_DEFENDER, "DEFENDER", "Defender" } ,
+ { CR_DEVOTION, "DEVOTION", "Sacrifice" } ,
+ { CR_GRANDCROSS, "GRANDCROSS", "Grand_Cross" } ,
+ { CR_HOLYCROSS, "HOLYCROSS", "Holy_Cross" } ,
+ { CR_PROVIDENCE, "PROVIDENCE", "Providence" } ,
+ { CR_REFLECTSHIELD, "REFLECTSHIELD", "Shield_Reflect" } ,
+ { CR_SHIELDBOOMERANG, "SHIELDBOOMERANG", "Shield_Boomerang" } ,
+ { CR_SHIELDCHARGE, "SHIELDCHARGE", "Shield_Charge" } ,
+ { CR_SPEARQUICKEN, "SPEARQUICKEN", "Spear_Quicken" } ,
+ { CR_SYNTHESISPOTION, "SYNTHESISPOTION", "Potion_Synthesis" } ,
+ { CR_TRUST, "TRUST", "Faith" } ,
+ { DC_DANCINGLESSON, "DANCINGLESSON", "Dancing_Lesson" } ,
+ { DC_DONTFORGETME, "DONTFORGETME", "Don't_Forget_Me" } ,
+ { DC_FORTUNEKISS, "FORTUNEKISS", "Fortune_Kiss" } ,
+ { DC_HUMMING, "HUMMING", "Humming" } ,
+ { DC_SCREAM, "SCREAM", "Scream" } ,
+ { DC_SERVICEFORYOU, "SERVICEFORYOU", "Prostitute" } ,
+ { DC_THROWARROW, "THROWARROW", "Throw_Arrow" } ,
+ { DC_UGLYDANCE, "UGLYDANCE", "Ugly_Dance" } ,
+ { HP_ASSUMPTIO, "ASSUMPTIO", "Assumptio" } ,
+ { HP_BASILICA, "BASILICA", "Basilica" } ,
+ { HP_MEDITATIO, "MEDITATIO", "Meditation" } ,
+ { HT_ANKLESNARE, "ANKLESNARE", "Ankle_Snare" } ,
+ { HT_BEASTBANE, "BEASTBANE", "Beast_Bane" } ,
+ { HT_BLASTMINE, "BLASTMINE", "Blast_Mine" } ,
+ { HT_BLITZBEAT, "BLITZBEAT", "Blitz_Beat" } ,
+ { HT_CLAYMORETRAP, "CLAYMORETRAP", "Claymore_Trap" } ,
+ { HT_DETECTING, "DETECTING", "Detect" } ,
+ { HT_FALCON, "FALCON", "Falconry_Mastery" } ,
+ { HT_FLASHER, "FLASHER", "Flasher" } ,
+ { HT_FREEZINGTRAP, "FREEZINGTRAP", "Freezing_Trap" } ,
+ { HT_LANDMINE, "LANDMINE", "Land_Mine" } ,
+ { HT_REMOVETRAP, "REMOVETRAP", "Remove_Trap" } ,
+ { HT_SANDMAN, "SANDMAN", "Sandman" } ,
+ { HT_SHOCKWAVE, "SHOCKWAVE", "Shockwave_Trap" } ,
+ { HT_SKIDTRAP, "SKIDTRAP", "Skid_Trap" } ,
+ { HT_SPRINGTRAP, "SPRINGTRAP", "Spring_Trap" } ,
+ { HT_STEELCROW, "STEELCROW", "Steel_Crow" } ,
+ { HT_TALKIEBOX, "TALKIEBOX", "Talkie_Box" } ,
+ { HW_MAGICCRASHER, "MAGICCRASHER", "Magic_Crasher" } ,
+ { HW_MAGICPOWER, "MAGICPOWER", "Magic_Power" } ,
+ { HW_NAPALMVULCAN, "NAPALMVULCAN", "Napalm_Vulcan" } ,
+ { HW_SOULDRAIN, "SOULDRAIN", "Soul_Drain" } ,
+ { KN_AUTOCOUNTER, "AUTOCOUNTER", "Counter_Attack" } ,
+ { KN_BOWLINGBASH, "BOWLINGBASH", "Bowling_Bash" } ,
+ { KN_BRANDISHSPEAR, "BRANDISHSPEAR", "Brandish_Spear" } ,
+ { KN_CAVALIERMASTERY, "CAVALIERMASTERY", "Cavalier_Mastery" } ,
+ { KN_PIERCE, "PIERCE", "Pierce" } ,
+ { KN_RIDING, "RIDING", "Peco_Peco_Ride" } ,
+ { KN_SPEARBOOMERANG, "SPEARBOOMERANG", "Spear_Boomerang" } ,
+ { KN_SPEARMASTERY, "SPEARMASTERY", "Spear_Mastery" } ,
+ { KN_SPEARSTAB, "SPEARSTAB", "Spear_Stab" } ,
+ { KN_TWOHANDQUICKEN, "TWOHANDQUICKEN", "Twohand_Quicken" } ,
+ { LK_AURABLADE, "AURABLADE", "Aura_Blade" } ,
+ { LK_BERSERK, "BERSERK", "Berserk" } ,
+ { LK_CONCENTRATION, "CONCENTRATION", "Concentration" } ,
+ { LK_FURY, "FURY", "LK_FURY" } ,
+ { LK_HEADCRUSH, "HEADCRUSH", "Head_Crusher" } ,
+ { LK_JOINTBEAT, "JOINTBEAT", "Joint_Beat" } ,
+ { LK_PARRYING, "PARRYING", "Parrying" } ,
+ { LK_SPIRALPIERCE, "SPIRALPIERCE", "Spiral_Pierce" } ,
+ { LK_TENSIONRELAX, "TENSIONRELAX", "Tension_Relax" } ,
+ { MC_CARTREVOLUTION, "CARTREVOLUTION", "Cart_Revolution" } ,
+ { MC_CHANGECART, "CHANGECART", "Change_Cart" } ,
+ { MC_DISCOUNT, "DISCOUNT", "Discount" } ,
+ { MC_IDENTIFY, "IDENTIFY", "Item_Appraisal" } ,
+ { MC_INCCARRY, "INCCARRY", "Enlarge_Weight_Limit" } ,
+ { MC_LOUD, "LOUD", "Lord_Exclamation" } ,
+ { MC_MAMMONITE, "MAMMONITE", "Mammonite" } ,
+ { MC_OVERCHARGE, "OVERCHARGE", "Overcharge" } ,
+ { MC_PUSHCART, "PUSHCART", "Pushcart" } ,
+ { MC_VENDING, "VENDING", "Vending" } ,
+ { MG_COLDBOLT, "COLDBOLT", "Cold_Bolt" } ,
+ { MG_ENERGYCOAT, "ENERGYCOAT", "Energy_Coat" } ,
+ { MG_FIREBALL, "FIREBALL", "Fire_Ball" } ,
+ { MG_FIREBOLT, "FIREBOLT", "Fire_Bolt" } ,
+ { MG_FIREWALL, "FIREWALL", "Fire_Wall" } ,
+ { MG_FROSTDIVER, "FROSTDIVER", "Frost_Diver" } ,
+ { MG_LIGHTNINGBOLT, "LIGHTNINGBOLT", "Lightening_Bolt" } ,
+ { MG_NAPALMBEAT, "NAPALMBEAT", "Napalm_Beat" } ,
+ { MG_SAFETYWALL, "SAFETYWALL", "Safety_Wall" } ,
+ { MG_SIGHT, "SIGHT", "Sight" } ,
+ { MG_SOULSTRIKE, "SOULSTRIKE", "Soul_Strike" } ,
+ { MG_SRECOVERY, "SRECOVERY", "Increase_SP_Recovery" } ,
+ { MG_STONECURSE, "STONECURSE", "Stone_Curse" } ,
+ { MG_THUNDERSTORM, "THUNDERSTORM", "Thunderstorm" } ,
+ { MO_ABSORBSPIRITS, "ABSORBSPIRITS", "Absorb_Spirits" } ,
+ { MO_BLADESTOP, "BLADESTOP", "Blade_Stop" } ,
+ { MO_BODYRELOCATION, "BODYRELOCATION", "Body_Relocation" } ,
+ { MO_CALLSPIRITS, "CALLSPIRITS", "Call_Spirits" } ,
+ { MO_CHAINCOMBO, "CHAINCOMBO", "Chain_Combo" } ,
+ { MO_COMBOFINISH, "COMBOFINISH", "Combo_Finish" } ,
+ { MO_DODGE, "DODGE", "Dodge" } ,
+ { MO_EXPLOSIONSPIRITS, "EXPLOSIONSPIRITS", "Explosion_Spirits" } ,
+ { MO_EXTREMITYFIST, "EXTREMITYFIST", "Extremity_Fist" } ,
+ { MO_FINGEROFFENSIVE, "FINGEROFFENSIVE", "Finger_Offensive" } ,
+ { MO_INVESTIGATE, "INVESTIGATE", "Investigate" } ,
+ { MO_IRONHAND, "IRONHAND", "Iron_Hand" } ,
+ { MO_SPIRITSRECOVERY, "SPIRITSRECOVERY", "Spirit_Recovery" } ,
+ { MO_STEELBODY, "STEELBODY", "Steel_Body" } ,
+ { MO_TRIPLEATTACK, "TRIPLEATTACK", "Triple_Blows" } ,
+ { NPC_ATTRICHANGE, "ATTRICHANGE", "NPC_ATTRICHANGE" } ,
+ { NPC_BARRIER, "BARRIER", "NPC_BARRIER" } ,
+ { NPC_BLINDATTACK, "BLINDATTACK", "NPC_BLINDATTACK" } ,
+ { NPC_BLOODDRAIN, "BLOODDRAIN", "NPC_BLOODDRAIN" } ,
+ { NPC_CHANGEDARKNESS, "CHANGEDARKNESS", "NPC_CHANGEDARKNESS" } ,
+ { NPC_CHANGEFIRE, "CHANGEFIRE", "NPC_CHANGEFIRE" } ,
+ { NPC_CHANGEGROUND, "CHANGEGROUND", "NPC_CHANGEGROUND" } ,
+ { NPC_CHANGEHOLY, "CHANGEHOLY", "NPC_CHANGEHOLY" } ,
+ { NPC_CHANGEPOISON, "CHANGEPOISON", "NPC_CHANGEPOISON" } ,
+ { NPC_CHANGETELEKINESIS, "CHANGETELEKINESIS", "NPC_CHANGETELEKINESIS" } ,
+ { NPC_CHANGEWATER, "CHANGEWATER", "NPC_CHANGEWATER" } ,
+ { NPC_CHANGEWIND, "CHANGEWIND", "NPC_CHANGEWIND" } ,
+ { NPC_COMBOATTACK, "COMBOATTACK", "NPC_COMBOATTACK" } ,
+ { NPC_CRITICALSLASH, "CRITICALSLASH", "NPC_CRITICALSLASH" } ,
+ { NPC_CURSEATTACK, "CURSEATTACK", "NPC_CURSEATTACK" } ,
+ { NPC_DARKBLESSING, "DARKBLESSING", "NPC_DARKBLESSING" } ,
+ { NPC_DARKBREATH, "DARKBREATH", "NPC_DARKBREATH" } ,
+ { NPC_DARKCROSS, "DARKCROSS", "NPC_DARKCROSS" } ,
+ { NPC_DARKNESSATTACK, "DARKNESSATTACK", "NPC_DARKNESSATTACK" } ,
+ { NPC_DEFENDER, "DEFENDER", "NPC_DEFENDER" } ,
+ { NPC_EMOTION, "EMOTION", "NPC_EMOTION" } ,
+ { NPC_ENERGYDRAIN, "ENERGYDRAIN", "NPC_ENERGYDRAIN" } ,
+ { NPC_FIREATTACK, "FIREATTACK", "NPC_FIREATTACK" } ,
+ { NPC_GROUNDATTACK, "GROUNDATTACK", "NPC_GROUNDATTACK" } ,
+ { NPC_GUIDEDATTACK, "GUIDEDATTACK", "NPC_GUIDEDATTACK" } ,
+ { NPC_HALLUCINATION, "HALLUCINATION", "NPC_HALLUCINATION" } ,
+ { NPC_HOLYATTACK, "HOLYATTACK", "NPC_HOLYATTACK" } ,
+ { NPC_KEEPING, "KEEPING", "NPC_KEEPING" } ,
+ { NPC_LICK, "LICK", "NPC_LICK" } ,
+ { NPC_MAGICALATTACK, "MAGICALATTACK", "NPC_MAGICALATTACK" } ,
+ { NPC_MENTALBREAKER, "MENTALBREAKER", "NPC_MENTALBREAKER" } ,
+ { NPC_METAMORPHOSIS, "METAMORPHOSIS", "NPC_METAMORPHOSIS" } ,
+ { NPC_PETRIFYATTACK, "PETRIFYATTACK", "NPC_PETRIFYATTACK" } ,
+ { NPC_PIERCINGATT, "PIERCINGATT", "NPC_PIERCINGATT" } ,
+ { NPC_POISON, "POISON", "NPC_POISON" } ,
+ { NPC_POISONATTACK, "POISONATTACK", "NPC_POISONATTACK" } ,
+ { NPC_PROVOCATION, "PROVOCATION", "NPC_PROVOCATION" } ,
+ { NPC_RANDOMATTACK, "RANDOMATTACK", "NPC_RANDOMATTACK" } ,
+ { NPC_RANGEATTACK, "RANGEATTACK", "NPC_RANGEATTACK" } ,
+ { NPC_REBIRTH, "REBIRTH", "NPC_REBIRTH" } ,
+ { NPC_SELFDESTRUCTION, "SELFDESTRUCTION", "Kabooooom!" } ,
+ { NPC_SELFDESTRUCTION2, "SELFDESTRUCTION2", "NPC_SELFDESTRUCTION2" } ,
+ { NPC_SILENCEATTACK, "SILENCEATTACK", "NPC_SILENCEATTACK" } ,
+ { NPC_SLEEPATTACK, "SLEEPATTACK", "NPC_SLEEPATTACK" } ,
+ { NPC_SMOKING, "SMOKING", "NPC_SMOKING" } ,
+ { NPC_SPLASHATTACK, "SPLASHATTACK", "NPC_SPLASHATTACK" } ,
+ { NPC_STUNATTACK, "STUNATTACK", "NPC_STUNATTACK" } ,
+ { NPC_SUICIDE, "SUICIDE", "NPC_SUICIDE" } ,
+ { NPC_SUMMONMONSTER, "SUMMONMONSTER", "NPC_SUMMONMONSTER" } ,
+ { NPC_SUMMONSLAVE, "SUMMONSLAVE", "NPC_SUMMONSLAVE" } ,
+ { NPC_TELEKINESISATTACK, "TELEKINESISATTACK", "NPC_TELEKINESISATTACK" } ,
+ { NPC_TRANSFORMATION, "TRANSFORMATION", "NPC_TRANSFORMATION" } ,
+ { NPC_WATERATTACK, "WATERATTACK", "NPC_WATERATTACK" } ,
+ { NPC_WINDATTACK, "WINDATTACK", "NPC_WINDATTACK" } ,
+ { NV_BASIC, "BASIC", "Basic_Skill" } ,
+ { NV_FIRSTAID, "FIRSTAID", "First Aid" } ,
+ { NV_TRICKDEAD, "TRICKDEAD", "Play_Dead" } ,
+ { PA_GOSPEL, "GOSPEL", "Gospel" } ,
+ { PA_PRESSURE, "PRESSURE", "Pressure" } ,
+ { PA_SACRIFICE, "SACRIFICE", "Sacrificial_Ritual" } ,
+ { PF_FOGWALL, "FOGWALL", "Wall_of_Fog" } ,
+ { PF_HPCONVERSION, "HPCONVERSION", "Health_Conversion" } ,
+ { PF_MEMORIZE, "MEMORIZE", "Memorize" } ,
+ { PF_MINDBREAKER, "MINDBREAKER", "Mind_Breaker" } ,
+ { PF_SOULBURN, "SOULBURN", "Soul_Burn" } ,
+ { PF_SOULCHANGE, "SOULCHANGE", "Soul_Change" } ,
+ { PF_SPIDERWEB, "SPIDERWEB", "Spider_Web" } ,
+ { PR_ASPERSIO, "ASPERSIO", "Aspersio" } ,
+ { PR_BENEDICTIO, "BENEDICTIO", "B.S_Sacramenti" } ,
+ { PR_GLORIA, "GLORIA", "Gloria" } ,
+ { PR_IMPOSITIO, "IMPOSITIO", "Impositio_Manus" } ,
+ { PR_KYRIE, "KYRIE", "Kyrie_Eleison" } ,
+ { PR_LEXAETERNA, "LEXAETERNA", "Lex_Aeterna" } ,
+ { PR_LEXDIVINA, "LEXDIVINA", "Lex_Divina" } ,
+ { PR_MACEMASTERY, "MACEMASTERY", "Mace_Mastery" } ,
+ { PR_MAGNIFICAT, "MAGNIFICAT", "Magnificat" } ,
+ { PR_MAGNUS, "MAGNUS", "Magnus_Exorcismus" } ,
+ { PR_SANCTUARY, "SANCTUARY", "Santuary" } ,
+ { PR_SLOWPOISON, "SLOWPOISON", "Slow_Poison" } ,
+ { PR_STRECOVERY, "STRECOVERY", "Status_Recovery" } ,
+ { PR_SUFFRAGIUM, "SUFFRAGIUM", "Suffragium" } ,
+ { PR_TURNUNDEAD, "TURNUNDEAD", "Turn_Undead" } ,
+ { RG_BACKSTAP, "BACKSTAP", "Back_Stab" } ,
+ { RG_CLEANER, "CLEANER", "Remover" } ,
+ { RG_COMPULSION, "COMPULSION", "Compulsion_Discount" } ,
+ { RG_FLAGGRAFFITI, "FLAGGRAFFITI", "Flag_Graffity" } ,
+ { RG_GANGSTER, "GANGSTER", "Gangster's_Paradise" } ,
+ { RG_GRAFFITI, "GRAFFITI", "Graffiti" } ,
+ { RG_INTIMIDATE, "INTIMIDATE", "Intimidate" } ,
+ { RG_PLAGIARISM, "PLAGIARISM", "Plagiarism" } ,
+ { RG_RAID, "RAID", "Raid" } ,
+ { RG_SNATCHER, "SNATCHER", "Snatcher" } ,
+ { RG_STEALCOIN, "STEALCOIN", "Steal_Coin" } ,
+ { RG_STRIPARMOR, "STRIPARMOR", "Strip_Armor" } ,
+ { RG_STRIPHELM, "STRIPHELM", "Strip_Helm" } ,
+ { RG_STRIPSHIELD, "STRIPSHIELD", "Strip_Shield" } ,
+ { RG_STRIPWEAPON, "STRIPWEAPON", "Strip_Weapon" } ,
+ { RG_TUNNELDRIVE, "TUNNELDRIVE", "Tunnel_Drive" } ,
+ { SA_ABRACADABRA, "ABRACADABRA", "Hocus-pocus" } ,
+ { SA_ADVANCEDBOOK, "ADVANCEDBOOK", "Advanced_Book" } ,
+ { SA_AUTOSPELL, "AUTOSPELL", "Auto_Cast" } ,
+ { SA_CASTCANCEL, "CASTCANCEL", "Cast_Cancel" } ,
+ { SA_CLASSCHANGE, "CLASSCHANGE", "Class_Change" } ,
+ { SA_COMA, "COMA", "Coma" } ,
+ { SA_DEATH, "DEATH", "Death" } ,
+ { SA_DELUGE, "DELUGE", "Deluge" } ,
+ { SA_DISPELL, "DISPELL", "Dispel" } ,
+ { SA_DRAGONOLOGY, "DRAGONOLOGY", "Dragonology" } ,
+ { SA_FLAMELAUNCHER, "FLAMELAUNCHER", "Flame_Launcher" } ,
+ { SA_FORTUNE, "FORTUNE", "Fortune" } ,
+ { SA_FREECAST, "FREECAST", "Cast_Freedom" } ,
+ { SA_FROSTWEAPON, "FROSTWEAPON", "Frost_Weapon" } ,
+ { SA_FULLRECOVERY, "FULLRECOVERY", "Full_Recovery" } ,
+ { SA_GRAVITY, "GRAVITY", "Gravity" } ,
+ { SA_INSTANTDEATH, "INSTANTDEATH", "Instant_Death" } ,
+ { SA_LANDPROTECTOR, "LANDPROTECTOR", "Land_Protector" } ,
+ { SA_LEVELUP, "LEVELUP", "Level_Up" } ,
+ { SA_LIGHTNINGLOADER, "LIGHTNINGLOADER", "Lightning_Loader" } ,
+ { SA_MAGICROD, "MAGICROD", "Magic_Rod" } ,
+ { SA_MONOCELL, "MONOCELL", "Monocell" } ,
+ { SA_QUESTION, "QUESTION", "Question?" } ,
+ { SA_REVERSEORCISH, "REVERSEORCISH", "Reverse_Orcish" } ,
+ { SA_SEISMICWEAPON, "SEISMICWEAPON", "Seismic_Weapon" } ,
+ { SA_SPELLBREAKER, "SPELLBREAKER", "Break_Spell" } ,
+ { SA_SUMMONMONSTER, "SUMMONMONSTER", "Summon_Monster" } ,
+ { SA_TAMINGMONSTER, "TAMINGMONSTER", "Taming_Monster" } ,
+ { SA_VIOLENTGALE, "VIOLENTGALE", "Violent_Gale" } ,
+ { SA_VOLCANO, "VOLCANO", "Volcano" } ,
+ { SG_DEVIL, "DEVIL", "Devil" } ,
+ { SG_FEEL, "FEEL", "Feel" } ,
+ { SG_FRIEND, "FRIEND", "Friend" } ,
+ { SG_FUSION, "FUSION", "Fusion" } ,
+ { SG_HATE, "HATE", "Hate" } ,
+ { SG_KNOWLEDGE, "KNOWLEDGE", "Knowledge" } ,
+ { SG_MOON_ANGER, "ANGER", "Moon Anger" } ,
+ { SG_MOON_BLESS, "BLESS", "Moon Bless" } ,
+ { SG_MOON_COMFORT, "COMFORT", "Moon Comfort" } ,
+ { SG_MOON_WARM, "WARM", "Moon Warm" } ,
+ { SG_STAR_ANGER, "ANGER", "Star Anger" } ,
+ { SG_STAR_BLESS, "BLESS", "Star Bless" } ,
+ { SG_STAR_COMFORT, "COMFORT", "Star Comfort" } ,
+ { SG_STAR_WARM, "WARM", "Star Warm" } ,
+ { SG_SUN_ANGER, "ANGER", "Sun Anger" } ,
+ { SG_SUN_BLESS, "BLESS", "Sun Bless" } ,
+ { SG_SUN_COMFORT, "COMFORT", "Sun Comfort" } ,
+ { SG_SUN_WARM, "WARM", "Sun Warm" } ,
+ { SL_ALCHEMIST, "ALCHEMIST", "Alchemist" } ,
+ { SL_ASSASIN, "ASSASIN", "Assasin" } ,
+ { SL_BARDDANCER, "BARDDANCER", "Bard Dancer" } ,
+ { SL_BLACKSMITH, "BLACKSMITH", "Black Smith" } ,
+ { SL_CRUSADER, "CRUSADER", "Crusader" } ,
+ { SL_HUNTER, "HUNTER", "Hunter" } ,
+ { SL_KAAHI, "KAAHI", "Kaahi" } ,
+ { SL_KAINA, "KAINA", "Kaina" } ,
+ { SL_KAITE, "KAITE", "Kaite" } ,
+ { SL_KAIZEL, "KAIZEL", "Kaizel" } ,
+ { SL_KAUPE, "KAUPE", "Kaupe" } ,
+ { SL_KNIGHT, "KNIGHT", "Knight" } ,
+ { SL_MONK, "MONK", "Monk" } ,
+ { SL_PRIEST, "PRIEST", "Priest" } ,
+ { SL_ROGUE, "ROGUE", "Rogue" } ,
+ { SL_SAGE, "SAGE", "Sage" } ,
+ { SL_SKA, "SKA", "SKA" } ,
+ { SL_SKE, "SKE", "SKE" } ,
+ { SL_SMA, "SMA", "SMA" } ,
+ { SL_SOULLINKER, "SOULLINKER", "Soul Linker" } ,
+ { SL_STAR, "STAR", "Star" } ,
+ { SL_STIN, "STIN", "Stin" } ,
+ { SL_STUN, "STUN", "Stun" } ,
+ { SL_SUPERNOVICE, "SUPERNOVICE", "Super Novice" } ,
+ { SL_SWOO, "SWOO", "Swoo" } ,
+ { SL_WIZARD, "WIZARD", "Wizard" } ,
+ { SM_AUTOBERSERK, "AUTOBERSERK", "Auto_Berserk" } ,
+ { SM_BASH, "BASH", "Bash" } ,
+ { SM_ENDURE, "ENDURE", "Endure" } ,
+ { SM_FATALBLOW, "FATALBLOW", "Attack_Weak_Point" } ,
+ { SM_MAGNUM, "MAGNUM", "Magnum_Break" } ,
+ { SM_MOVINGRECOVERY, "MOVINGRECOVERY", "Moving_HP_Recovery" } ,
+ { SM_PROVOKE, "PROVOKE", "Provoke" } ,
+ { SM_RECOVERY, "RECOVERY", "Increase_HP_Recovery" } ,
+ { SM_SWORD, "SWORD", "Sword_Mastery" } ,
+ { SM_TWOHAND, "TWOHAND", "Two-Handed_Sword_Mastery" } ,
+ { SN_FALCONASSAULT, "FALCONASSAULT", "Falcon_Assault" } ,
+ { SN_SHARPSHOOTING, "SHARPSHOOTING", "Sharpshooting" } ,
+ { SN_SIGHT, "SIGHT", "True_Sight" } ,
+ { SN_WINDWALK, "WINDWALK", "Wind_Walk" } ,
+ { ST_CHASEWALK, "CHASEWALK", "Chase_Walk" } ,
+ { ST_REJECTSWORD, "REJECTSWORD", "Reject_Sword" } ,
+ { ST_STEALBACKPACK, "STEALBACKPACK", "Steal_Backpack" } ,
+ { TF_BACKSLIDING, "BACKSLIDING", "Back_Sliding" } ,
+ { TF_DETOXIFY, "DETOXIFY", "Detoxify" } ,
+ { TF_DOUBLE, "DOUBLE", "Double_Attack" } ,
+ { TF_HIDING, "HIDING", "Hiding" } ,
+ { TF_MISS, "MISS", "Improve_Dodge" } ,
+ { TF_PICKSTONE, "PICKSTONE", "Take_Stone" } ,
+ { TF_POISON, "POISON", "Envenom" } ,
+ { TF_SPRINKLESAND, "SPRINKLESAND", "Throw_Sand" } ,
+ { TF_STEAL, "STEAL", "Steal" } ,
+ { TF_THROWSTONE, "THROWSTONE", "Throw_Stone" } ,
+ { TK_COUNTER, "COUNTER", "Counter" } ,
+ { TK_DODGE, "DODGE", "Dodge" } ,
+ { TK_DOWNKICK, "DOWNKICK", "Down Kick" } ,
+ { TK_HIGHJUMP, "HIGHJUMP", "High Jump" } ,
+ { TK_HPTIME, "HPTIME", "HP Time" } ,
+ { TK_JUMPKICK, "JUMPKICK", "Jump Kick" } ,
+ { TK_POWER, "POWER", "Power" } ,
+ { TK_READYCOUNTER, "READYCOUNTER", "Ready Counter" } ,
+ { TK_READYDOWN, "READYDOWN", "Ready Down" } ,
+ { TK_READYSTORM, "READYSTORM", "Ready Storm" } ,
+ { TK_READYTURN, "READYTURN", "Ready Turn" } ,
+ { TK_RUN, "RUN", "TK_RUN" } ,
+ { TK_SEVENWIND, "SEVENWIND", "Seven Wind" } ,
+ { TK_SPTIME, "SPTIME", "SP Time" } ,
+ { TK_STORMKICK, "STORMKICK", "Storm Kick" } ,
+ { TK_TURNKICK, "TURNKICK", "Turn Kick" } ,
+ { WE_BABY, "BABY", "Adopt_Baby" } ,
+ { WE_CALLBABY, "CALLBABY", "Call_Baby" } ,
+ { WE_CALLPARENT, "CALLPARENT", "Call_Parent" } ,
+ { WE_CALLPARTNER, "CALLPARTNER", "I Want to See You" } ,
+ { WE_FEMALE, "FEMALE", "I Only Look Up to You" } ,
+ { WE_MALE, "MALE", "I Will Protect You" } ,
+ { WS_CARTBOOST, "CARTBOOST", "Cart_Boost" } ,
+ { WS_CREATECOIN, "CREATECOIN", "Create_Coins" } ,
+ { WS_CREATENUGGET, "CREATENUGGET", "Create_Nuggets" } ,
+ { WS_MELTDOWN, "MELTDOWN", "Meltdown" } ,
+ { WS_SYSTEMCREATE, "SYSTEMCREATE", "Create_System_tower" } ,
+ { WZ_EARTHSPIKE, "EARTHSPIKE", "Earth_Spike" } ,
+ { WZ_ESTIMATION, "ESTIMATION", "Sense" } ,
+ { WZ_FIREIVY, "FIREIVY", "Fire_Ivy" } ,
+ { WZ_FIREPILLAR, "FIREPILLAR", "Fire_Pillar" } ,
+ { WZ_FROSTNOVA, "FROSTNOVA", "Frost_Nova" } ,
+ { WZ_HEAVENDRIVE, "HEAVENDRIVE", "Heaven's_Drive" } ,
+ { WZ_ICEWALL, "ICEWALL", "Ice_Wall" } ,
+ { WZ_JUPITEL, "JUPITEL", "Jupitel_Thunder" } ,
+ { WZ_METEOR, "METEOR", "Meteor_Storm" } ,
+ { WZ_QUAGMIRE, "QUAGMIRE", "Quagmire" } ,
+ { WZ_SIGHTRASHER, "SIGHTRASHER", "Sightrasher" } ,
+ { WZ_STORMGUST, "STORMGUST", "Storm_Gust" } ,
+ { WZ_VERMILION, "VERMILION", "Lord_of_Vermilion" } ,
+ { WZ_WATERBALL, "WATERBALL", "Water_Ball" } ,
+ { 0, 0, 0 }
+};
+
+static const int dirx[8]={0,-1,-1,-1,0,1,1,1};
+static const int diry[8]={1,1,0,-1,-1,-1,0,1};
+
+static int rdamage;
+
+/* スキルデータベース */
+struct skill_db skill_db[MAX_SKILL_DB];
+
+/* アイテム作成データベース */
+struct skill_produce_db skill_produce_db[MAX_SKILL_PRODUCE_DB];
+
+/* 矢作成スキルデータベース */
+struct skill_arrow_db skill_arrow_db[MAX_SKILL_ARROW_DB];
+
+/* アブラカダブラ発動スキルデータベース */
+struct skill_abra_db skill_abra_db[MAX_SKILL_ABRA_DB];
+
+int skill_get_hit( int id ){ return skill_db[id].hit; }
+int skill_get_inf( int id ){ return skill_db[id].inf; }
+int skill_get_pl( int id ){ return skill_db[id].pl; }
+int skill_get_nk( int id ){ return skill_db[id].nk; }
+int skill_get_max( int id ){ return skill_db[id].max; }
+int skill_get_range( int id , int lv ){ return (lv <= 0) ? 0:skill_db[id].range[lv-1]; }
+int skill_get_hp( int id ,int lv ){ return (lv <= 0) ? 0:skill_db[id].hp[lv-1]; }
+int skill_get_sp( int id ,int lv ){ return (lv <= 0) ? 0:skill_db[id].sp[lv-1]; }
+int skill_get_zeny( int id ,int lv ){ return (lv <= 0) ? 0:skill_db[id].zeny[lv-1]; }
+int skill_get_num( int id ,int lv ){ return (lv <= 0) ? 0:skill_db[id].num[lv-1]; }
+int skill_get_cast( int id ,int lv ){ return (lv <= 0) ? 0:skill_db[id].cast[lv-1]; }
+int skill_get_delay( int id ,int lv ){ return (lv <= 0) ? 0:skill_db[id].delay[lv-1]; }
+int skill_get_time( int id ,int lv ){ return (lv <= 0) ? 0:skill_db[id].upkeep_time[lv-1]; }
+int skill_get_time2( int id ,int lv ){ return (lv <= 0) ? 0:skill_db[id].upkeep_time2[lv-1]; }
+int skill_get_castdef( int id ){ return skill_db[id].cast_def_rate; }
+int skill_get_weapontype( int id ){ return skill_db[id].weapon; }
+int skill_get_inf2( int id ){ return skill_db[id].inf2; }
+int skill_get_maxcount( int id ){ return skill_db[id].maxcount; }
+int skill_get_blewcount( int id ,int lv ){ return (lv <= 0) ? 0:skill_db[id].blewcount[lv-1]; }
+int skill_get_mhp( int id ,int lv ){ return (lv <= 0) ? 0:skill_db[id].mhp[lv-1]; }
+int skill_get_castnodex( int id ,int lv ){ return (lv <= 0) ? 0:skill_db[id].castnodex[lv-1]; }
+
+/* プロトタイプ */
+struct skill_unit_group *skill_unitsetting( struct block_list *src, int skillid,int skilllv,int x,int y,int flag);
+int skill_check_condition( struct map_session_data *sd,int type);
+int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag );
+int skill_frostjoke_scream(struct block_list *bl,va_list ap);
+int skill_status_change_timer_sub(struct block_list *bl, va_list ap );
+int skill_attack_area(struct block_list *bl,va_list ap);
+int skill_abra_dataset(int skilllv);
+int skill_clear_element_field(struct block_list *bl);
+int skill_landprotector(struct block_list *bl, va_list ap );
+int skill_trap_splash(struct block_list *bl, va_list ap );
+int skill_count_target(struct block_list *bl, va_list ap );
+
+// [MouseJstr] - skill ok to cast? and when?
+int skillnotok(int skillid, struct map_session_data *sd) {
+ if (sd == 0)
+ return 0;
+ if (pc_isGM(sd) >= 20)
+ return 0; // gm's can do anything damn thing they want
+ switch (skillid) {
+ case AL_WARP:
+ case AL_TELEPORT:
+ case MC_VENDING:
+ case MC_IDENTIFY:
+ return 0; // always allowed
+ default:
+ return(map[sd->bl.m].flag.noskill);
+ }
+}
+
+
+static int distance(int x0,int y0,int x1,int y1)
+{
+ int dx,dy;
+
+ dx=abs(x0-x1);
+ dy=abs(y0-y1);
+ return dx>dy ? dx : dy;
+}
+
+/* スキルユニットIDを返す(これもデータベースに入れたいな) */
+int skill_get_unit_id(int id,int flag)
+{
+
+ switch(id){
+ case MG_SAFETYWALL: return 0x7e; /* セイフティウォール */
+ case MG_FIREWALL: return 0x7f; /* ファイアーウォール */
+ case AL_WARP: return (flag==0)?0x81:0x80; /* ワープポータル */
+ case PR_BENEDICTIO: return 0x82; /* 聖体降福 */
+ case PR_SANCTUARY: return 0x83; /* サンクチュアリ */
+ case PR_MAGNUS: return 0x84; /* マグヌスエクソシズム */
+ case AL_PNEUMA: return 0x85; /* ニューマ */
+ case MG_THUNDERSTORM: return 0x86; /* サンダーストーム */
+ case WZ_HEAVENDRIVE: return 0x86; /* ヘヴンズドライブ */
+ case WZ_SIGHTRASHER: return 0x86; /* サイトラッシャー */
+ case WZ_METEOR: return 0x86; /* メテオストーム */
+ case WZ_VERMILION: return 0x86; /* ロードオブヴァーミリオン */
+ case WZ_FROSTNOVA: return 0x86; /* フロストノヴァ */
+ case WZ_STORMGUST: return 0x86; /* ストームガスト(とりあえずLoVと同じで処理) */
+ case CR_GRANDCROSS: return 0x86; /* グランドクロス */
+ case WZ_FIREPILLAR: return (flag==0)?0x87:0x88; /* ファイアーピラー */
+ case HT_TALKIEBOX: return 0x99; /* トーキーボックス */
+ case WZ_ICEWALL: return 0x8d; /* アイスウォール */
+ case WZ_QUAGMIRE: return 0x8e; /* クァグマイア */
+ case HT_BLASTMINE: return 0x8f; /* ブラストマイン */
+ case HT_SKIDTRAP: return 0x90; /* スキッドトラップ */
+ case HT_ANKLESNARE: return 0x91; /* アンクルスネア */
+ case AS_VENOMDUST: return 0x92; /* ベノムダスト */
+ case HT_LANDMINE: return 0x93; /* ランドマイン */
+ case HT_SHOCKWAVE: return 0x94; /* ショックウェーブトラップ */
+ case HT_SANDMAN: return 0x95; /* サンドマン */
+ case HT_FLASHER: return 0x96; /* フラッシャー */
+ case HT_FREEZINGTRAP: return 0x97; /* フリージングトラップ */
+ case HT_CLAYMORETRAP: return 0x98; /* クレイモアートラップ */
+ case SA_VOLCANO: return 0x9a; /* ボルケーノ */
+ case SA_DELUGE: return 0x9b; /* デリュージ */
+ case SA_VIOLENTGALE: return 0x9c; /* バイオレントゲイル */
+ case SA_LANDPROTECTOR: return 0x9d; /* ランドプロテクター */
+ case BD_LULLABY: return 0x9e; /* 子守歌 */
+ case BD_RICHMANKIM: return 0x9f; /* ニヨルドの宴 */
+ case BD_ETERNALCHAOS: return 0xa0; /* 永遠の混沌 */
+ case BD_DRUMBATTLEFIELD:return 0xa1; /* 戦太鼓の響き */
+ case BD_RINGNIBELUNGEN: return 0xa2; /* ニーベルングの指輪 */
+ case BD_ROKISWEIL: return 0xa3; /* ロキの叫び */
+ case BD_INTOABYSS: return 0xa4; /* 深淵の中に */
+ case BD_SIEGFRIED: return 0xa5; /* 不死身のジークフリード */
+ case BA_DISSONANCE: return 0xa6; /* 不協和音 */
+ case BA_WHISTLE: return 0xa7; /* 口笛 */
+ case BA_ASSASSINCROSS: return 0xa8; /* 夕陽のアサシンクロス */
+ case BA_POEMBRAGI: return 0xa9; /* ブラギの詩 */
+ case BA_APPLEIDUN: return 0xaa; /* イドゥンの林檎 */
+ case DC_UGLYDANCE: return 0xab; /* 自分勝手なダンス */
+ case DC_HUMMING: return 0xac; /* ハミング */
+ case DC_DONTFORGETME: return 0xad; /* 私を忘れないで… */
+ case DC_FORTUNEKISS: return 0xae; /* 幸運のキス */
+ case DC_SERVICEFORYOU: return 0xaf; /* サービスフォーユー */
+ case RG_GRAFFITI: return 0xb0; /* グラフィティ */
+ case AM_DEMONSTRATION: return 0xb1; /* デモンストレーション */
+ case WE_CALLPARTNER: return 0xb2; /* あなたに逢いたい */
+ case PA_GOSPEL: return 0xb3; /* ゴスペル */
+ case HP_BASILICA: return 0xb4; /* バジリカ */
+ case PF_FOGWALL: return 0xb6; /* フォグウォール */
+ case PF_SPIDERWEB: return 0xb7; /* スパイダーウェッブ */
+ }
+ return 0;
+ /*
+ 0x89,0x8a,0x8b 表示無し
+ 0x9a 炎属性の詠唱みたいなエフェクト
+ 0x9b 水属性の詠唱みたいなエフェクト
+ 0x9c 風属性の詠唱みたいなエフェクト
+ 0x9d 白い小さなエフェクト
+ 0xb1 Alchemist Demonstration
+ 0xb2 = Pink Warp Portal
+ 0xb3 = Gospel For Paladin
+ 0xb4 = Basilica
+ 0xb5 = Empty
+ 0xb6 = Fog Wall for Professor
+ 0xb7 = Spider Web for Professor
+ 0xb8 = Empty
+ 0xb9 =
+ */
+}
+
+/*==========================================
+ * スキル追加効果
+ *------------------------------------------
+ */
+int skill_additional_effect( struct block_list* src, struct block_list *bl,int skillid,int skilllv,int attack_type,unsigned int tick)
+{
+ /* MOB追加効果スキル用 */
+ const int sc[]={
+ SC_POISON, SC_BLIND, SC_SILENCE, SC_STAN,
+ SC_STONE, SC_CURSE, SC_SLEEP
+ };
+ const int sc2[]={
+ MG_STONECURSE,MG_FROSTDIVER,NPC_STUNATTACK,
+ NPC_SLEEPATTACK,TF_POISON,NPC_CURSEATTACK,
+ NPC_SILENCEATTACK,0,NPC_BLINDATTACK
+ };
+
+ struct map_session_data *sd=NULL;
+ struct map_session_data *dstsd=NULL;
+ struct mob_data *md=NULL;
+ struct mob_data *dstmd=NULL;
+ struct pet_data *pd=NULL;
+
+ int skill,skill2;
+ int rate,luk;
+
+ int sc_def_mdef,sc_def_vit,sc_def_int,sc_def_luk;
+ int sc_def_mdef2,sc_def_vit2,sc_def_int2,sc_def_luk2;
+
+ nullpo_retr(0, src);
+ nullpo_retr(0, bl);
+
+ if(skilllv < 0) return 0;
+
+ if(src->type==BL_PC){
+ nullpo_retr(0, sd=(struct map_session_data *)src);
+ }else if(src->type==BL_MOB){
+ nullpo_retr(0, md=(struct mob_data *)src); //未使用?
+ }else if(src->type==BL_PET){
+ nullpo_retr(0, pd=(struct pet_data *)src); // [Valaris]
+ }
+
+ //対象の耐性
+ luk = battle_get_luk(bl);
+ sc_def_mdef=100 - (3 + battle_get_mdef(bl) + luk/3);
+ sc_def_vit=100 - (3 + battle_get_vit(bl) + luk/3);
+ sc_def_int=100 - (3 + battle_get_int(bl) + luk/3);
+ sc_def_luk=100 - (3 + luk);
+ //自分の耐性
+ luk = battle_get_luk(src);
+ sc_def_mdef2=100 - (3 + battle_get_mdef(src) + luk/3);
+ sc_def_vit2=100 - (3 + battle_get_vit(src) + luk/3);
+ sc_def_int2=100 - (3 + battle_get_int(src) + luk/3);
+ sc_def_luk2=100 - (3 + luk);
+ if(bl->type==BL_PC)
+ dstsd=(struct map_session_data *)bl;
+ else if(bl->type==BL_MOB){
+ dstmd=(struct mob_data *)bl; //未使用?
+ if(sc_def_mdef>50)
+ sc_def_mdef=50;
+ if(sc_def_vit>50)
+ sc_def_vit=50;
+ if(sc_def_int>50)
+ sc_def_int=50;
+ if(sc_def_luk>50)
+ sc_def_luk=50;
+ }
+ if(sc_def_mdef<0)
+ sc_def_mdef=0;
+ if(sc_def_vit<0)
+ sc_def_vit=0;
+ if(sc_def_int<0)
+ sc_def_int=0;
+
+ switch(skillid){
+ case 0: /* 通常攻撃 */
+ /* 自動鷹 */
+ if( sd && pc_isfalcon(sd) && sd->status.weapon == 11 && (skill=pc_checkskill(sd,HT_BLITZBEAT))>0 &&
+ rand()%1000 <= sd->paramc[5]*10/3+1 ) {
+ int lv=(sd->status.job_level+9)/10;
+ skill_castend_damage_id(src,bl,HT_BLITZBEAT,(skill<lv)?skill:lv,tick,0xf00000);
+ }
+ // スナッチャー
+ if(sd && sd->status.weapon != 11 && (skill=pc_checkskill(sd,RG_SNATCHER)) > 0)
+ if((skill*15 + 55) + (skill2 = pc_checkskill(sd,TF_STEAL))*10 > rand()%1000) {
+ if(pc_steal_item(sd,bl))
+ clif_skill_nodamage(src,bl,TF_STEAL,skill2,1);
+ else
+ clif_skill_fail(sd,skillid,0,0);
+ }
+ break;
+
+ case SM_BASH: /* バッシュ(急所攻撃) */
+ if( sd && (skill=pc_checkskill(sd,SM_FATALBLOW))>0 ){
+ if( rand()%100 < 6*(skilllv-5)*sc_def_vit/100 )
+ skill_status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(SM_FATALBLOW,skilllv),0);
+ }
+ break;
+
+ case TF_POISON: /* インベナム */
+ case AS_SPLASHER: /* ベナムスプラッシャー */
+ if(rand()%100< (2*skilllv+10)*sc_def_vit/100 )
+ skill_status_change_start(bl,SC_POISON,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ else{
+ if(sd && skillid==TF_POISON)
+ clif_skill_fail(sd,skillid,0,0);
+ }
+ break;
+
+ case AS_SONICBLOW: /* ソニックブロー */
+ if( rand()%100 < (2*skilllv+10)*sc_def_vit/100 )
+ skill_status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+
+
+ case HT_FREEZINGTRAP: /* フリージングトラップ */
+ rate=skilllv*3+35;
+ if(rand()%100 < rate*sc_def_mdef/100)
+ skill_status_change_start(bl,SC_FREEZE,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+
+ case MG_FROSTDIVER: /* フロストダイバー */
+ case WZ_FROSTNOVA: /* フロストノヴァ */
+ rate=(skilllv*3+35)*sc_def_mdef/100-(battle_get_int(bl)+battle_get_luk(bl))/15;
+ rate=rate<=5?5:rate;
+ if(rand()%100 < rate)
+ skill_status_change_start(bl,SC_FREEZE,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ else if(sd)
+ clif_skill_fail(sd,skillid,0,0);
+ break;
+
+ case WZ_STORMGUST: /* ストームガスト */
+ {
+ struct status_change *sc_data = battle_get_sc_data(bl);
+ if(sc_data) {
+ sc_data[SC_FREEZE].val3++;
+ if(sc_data[SC_FREEZE].val3 >= 3)
+ skill_status_change_start(bl,SC_FREEZE,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ }
+ }
+ break;
+
+ case HT_LANDMINE: /* ランドマイン */
+ if( rand()%100 < (5*skilllv+30)*sc_def_vit/100 )
+ skill_status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+
+ case HT_SHOCKWAVE: /* ショックウェーブトラップ */
+ if(map[bl->m].flag.pvp && dstsd){
+ dstsd->status.sp -= dstsd->status.sp*(5+15*skilllv)/100;
+ pc_calcstatus(dstsd,0);
+ }
+ break;
+ case HT_SANDMAN: /* サンドマン */
+ if( rand()%100 < (5*skilllv+30)*sc_def_int/100 )
+ skill_status_change_start(bl,SC_SLEEP,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+ case TF_SPRINKLESAND: /* 砂まき */
+ if( rand()%100 < 15*sc_def_int/100 )
+ skill_status_change_start(bl,SC_BLIND,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+
+ case TF_THROWSTONE: /* 石投げ */
+ if( rand()%100 < 5*sc_def_vit/100 )
+ skill_status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+
+ case CR_HOLYCROSS: /* ホーリークロス */
+ if( rand()%100 < 3*skilllv*sc_def_int/100 )
+ skill_status_change_start(bl,SC_BLIND,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+
+ case CR_GRANDCROSS: /* グランドクロス */
+ {
+ int race = battle_get_race(bl);
+ if( (battle_check_undead(race,battle_get_elem_type(bl)) || race == 6) && rand()%100 < 100000*sc_def_int/100) //強制付与だが完全耐性には無効
+ skill_status_change_start(bl,SC_BLIND,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ }
+ break;
+
+ case CR_SHIELDCHARGE: /* シールドチャージ */
+ if( rand()%100 < (15 + skilllv*5)*sc_def_vit/100 )
+ skill_status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+
+ case RG_RAID: /* サプライズアタック */
+ if( rand()%100 < (10+3*skilllv)*sc_def_vit/100 )
+ skill_status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ if( rand()%100 < (10+3*skilllv)*sc_def_int/100 )
+ skill_status_change_start(bl,SC_BLIND,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+ case BA_FROSTJOKE:
+ if(rand()%100 < (15+5*skilllv)*sc_def_mdef/100)
+ skill_status_change_start(bl,SC_FREEZE,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+
+ case DC_SCREAM:
+ if( rand()%100 < (25+5*skilllv)*sc_def_vit/100 )
+ skill_status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+
+ case BD_LULLABY: /* 子守唄 */
+ if( rand()%100 < 15*sc_def_int/100 )
+ skill_status_change_start(bl,SC_SLEEP,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+
+ /* MOBの追加効果付きスキル */
+
+ case NPC_PETRIFYATTACK:
+ if(rand()%100 < sc_def_mdef)
+ skill_status_change_start(bl,sc[skillid-NPC_POISON],skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+ case NPC_POISON:
+ case NPC_SILENCEATTACK:
+ case NPC_STUNATTACK:
+ if(rand()%100 < sc_def_vit && src->type!=BL_PET)
+ skill_status_change_start(bl,sc[skillid-NPC_POISON],skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ if(src->type==BL_PET)
+ skill_status_change_start(bl,sc[skillid-NPC_POISON],skilllv,0,0,0,skilllv*1000,0);
+ break;
+ case NPC_CURSEATTACK:
+ if(rand()%100 < sc_def_luk)
+ skill_status_change_start(bl,sc[skillid-NPC_POISON],skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+ case NPC_SLEEPATTACK:
+ case NPC_BLINDATTACK:
+ if(rand()%100 < sc_def_int)
+ skill_status_change_start(bl,sc[skillid-NPC_POISON],skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+ case NPC_MENTALBREAKER:
+ if(dstsd) {
+ int sp = dstsd->status.max_sp*(10+skilllv)/100;
+ if(sp < 1) sp = 1;
+ pc_heal(dstsd,0,-sp);
+ }
+ break;
+
+// -- moonsoul (adding status effect chance given to wizard aoe skills meteor and vermillion)
+//
+ case WZ_METEOR:
+ if(rand()%100 < sc_def_vit)
+ skill_status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+ case WZ_VERMILION:
+ if(rand()%100 < sc_def_int)
+ skill_status_change_start(bl,SC_BLIND,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+
+// -- moonsoul (stun ability of new champion skill tigerfist)
+//
+ case CH_TIGERFIST:
+ if( rand()%100 < (5 + skilllv*5)*sc_def_vit/100 )
+ skill_status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+
+ case LK_SPIRALPIERCE:
+ if( rand()%100 < (15 + skilllv*5)*sc_def_vit/100 )
+ skill_status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+ case ST_REJECTSWORD: /* フリージングトラップ */
+ if( rand()%100 < (10 + skilllv*5) )
+ skill_status_change_start(bl,SC_AUTOCOUNTER,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+ case PF_FOGWALL: /* ホーリークロス */
+ if( rand()%100 < 3*skilllv*sc_def_int/100 )
+ skill_status_change_start(bl,SC_BLIND,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+ case LK_HEADCRUSH: /* ヘッドクラッシュ */
+ {//条件が良く分からないので適当に
+ int race=battle_get_race(bl);
+ if( !(battle_check_undead(race,battle_get_elem_type(bl)) || race == 6) && rand()%100 < (2*skilllv+10)*sc_def_vit/100 )
+ skill_status_change_start(bl,SC_HEADCRUSH,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ }
+ break;
+ case LK_JOINTBEAT: /* ジョイントビート */
+ //条件が良く分からないので適当に
+ if( rand()%100 < (2*skilllv+10)*sc_def_vit/100 )
+ skill_status_change_start(bl,SC_JOINTBEAT,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+ case PF_SPIDERWEB: /* スパイダーウェッブ */
+ {
+ int sec=skill_get_time2(skillid,skilllv);
+ if(map[src->m].flag.pvp) //PvPでは拘束時間半減?
+ sec = sec/2;
+ battle_stopwalking(bl,1);
+ skill_status_change_start(bl,SC_SPIDERWEB,skilllv,0,0,0,sec,0);
+ }
+ break;
+ case ASC_METEORASSAULT: /* メテオアサルト */
+ if( rand()%100 < (15 + skilllv*5)*sc_def_vit/100 ) //状態異常は詳細が分からないので適当に
+ skill_status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ if( rand()%100 < (10+3*skilllv)*sc_def_int/100 )
+ skill_status_change_start(bl,SC_BLIND,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+ case MO_EXTREMITYFIST: /* 阿修羅覇凰拳 */
+ //阿修羅を使うと5分間自然回復しないようになる
+ skill_status_change_start(src,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time2(skillid,skilllv),0 );
+ break;
+ }
+
+ if(sd && skillid != MC_CARTREVOLUTION && attack_type&BF_WEAPON){ /* カードによる追加効果 */
+ int i;
+ int sc_def_card=100;
+
+ for(i=SC_STONE;i<=SC_BLIND;i++){
+ //対象に状態異常
+ if(i==SC_STONE || i==SC_FREEZE)
+ sc_def_card=sc_def_mdef;
+ else if(i==SC_STAN || i==SC_POISON || i==SC_SILENCE)
+ sc_def_card=sc_def_vit;
+ else if(i==SC_SLEEP || i==SC_CONFUSION || i==SC_BLIND)
+ sc_def_card=sc_def_int;
+ else if(i==SC_CURSE)
+ sc_def_card=sc_def_luk;
+
+ if(!sd->state.arrow_atk) {
+ if(rand()%10000 < (sd->addeff[i-SC_STONE])*sc_def_card/100 ){
+ if(battle_config.battle_log)
+ printf("PC %d skill_addeff: cardによる異常発動 %d %d\n",sd->bl.id,i,sd->addeff[i-SC_STONE]);
+ skill_status_change_start(bl,i,7,0,0,0,(i==SC_CONFUSION)? 10000+7000:skill_get_time2(sc2[i-SC_STONE],7),0);
+ }
+ }
+ else {
+ if(rand()%10000 < (sd->addeff[i-SC_STONE]+sd->arrow_addeff[i-SC_STONE])*sc_def_card/100 ){
+ if(battle_config.battle_log)
+ printf("PC %d skill_addeff: cardによる異常発動 %d %d\n",sd->bl.id,i,sd->addeff[i-SC_STONE]);
+ skill_status_change_start(bl,i,7,0,0,0,(i==SC_CONFUSION)? 10000+7000:skill_get_time2(sc2[i-SC_STONE],7),0);
+ }
+ }
+ //自分に状態異常
+ if(i==SC_STONE || i==SC_FREEZE)
+ sc_def_card=sc_def_mdef2;
+ else if(i==SC_STAN || i==SC_POISON || i==SC_SILENCE)
+ sc_def_card=sc_def_vit2;
+ else if(i==SC_SLEEP || i==SC_CONFUSION || i==SC_BLIND)
+ sc_def_card=sc_def_int2;
+ else if(i==SC_CURSE)
+ sc_def_card=sc_def_luk2;
+
+ if(!sd->state.arrow_atk) {
+ if(rand()%10000 < (sd->addeff2[i-SC_STONE])*sc_def_card/100 ){
+ if(battle_config.battle_log)
+ printf("PC %d skill_addeff: cardによる異常発動 %d %d\n",src->id,i,sd->addeff2[i-SC_STONE]);
+ skill_status_change_start(src,i,7,0,0,0,(i==SC_CONFUSION)? 10000+7000:skill_get_time2(sc2[i-SC_STONE],7),0);
+ }
+ }
+ else {
+ if(rand()%10000 < (sd->addeff2[i-SC_STONE]+sd->arrow_addeff2[i-SC_STONE])*sc_def_card/100 ){
+ if(battle_config.battle_log)
+ printf("PC %d skill_addeff: cardによる異常発動 %d %d\n",src->id,i,sd->addeff2[i-SC_STONE]);
+ skill_status_change_start(src,i,7,0,0,0,(i==SC_CONFUSION)? 10000+7000:skill_get_time2(sc2[i-SC_STONE],7),0);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*=========================================================================
+ スキル攻撃吹き飛ばし処理
+-------------------------------------------------------------------------*/
+int skill_blown( struct block_list *src, struct block_list *target,int count)
+{
+ int dx=0,dy=0,nx,ny;
+ int x=target->x,y=target->y;
+ int ret,prev_state=MS_IDLE;
+ int moveblock;
+ struct map_session_data *sd=NULL;
+ struct mob_data *md=NULL;
+ struct pet_data *pd=NULL;
+ struct skill_unit *su=NULL;
+
+ nullpo_retr(0, src);
+ nullpo_retr(0, target);
+
+ if(target->type==BL_PC){
+ nullpo_retr(0, sd=(struct map_session_data *)target);
+ }else if(target->type==BL_MOB){
+ nullpo_retr(0, md=(struct mob_data *)target);
+ }else if(target->type==BL_PET){
+ nullpo_retr(0, pd=(struct pet_data *)target);
+ }else if(target->type==BL_SKILL){
+ nullpo_retr(0, su=(struct skill_unit *)target);
+ }else return 0;
+
+ if(!(count&0x10000 && (sd||md||pd||su))){ /* 指定なしなら位置関係から方向を求める */
+ dx=target->x-src->x; dx=(dx>0)?1:((dx<0)?-1: 0);
+ dy=target->y-src->y; dy=(dy>0)?1:((dy<0)?-1: 0);
+ }
+ if(dx==0 && dy==0){
+ int dir=battle_get_dir(target);
+ if(dir>=0 && dir<8){
+ dx=-dirx[dir];
+ dy=-diry[dir];
+ }
+ }
+
+ ret=path_blownpos(target->m,x,y,dx,dy,count&0xffff);
+ nx=ret>>16;
+ ny=ret&0xffff;
+ moveblock=( x/BLOCK_SIZE != nx/BLOCK_SIZE || y/BLOCK_SIZE != ny/BLOCK_SIZE);
+
+ if(count&0x20000) {
+ battle_stopwalking(target,1);
+ if(sd){
+ sd->to_x=nx;
+ sd->to_y=ny;
+ sd->walktimer = 1;
+ clif_walkok(sd);
+ clif_movechar(sd);
+ }
+ else if(md) {
+ md->to_x=nx;
+ md->to_y=ny;
+ prev_state = md->state.state;
+ md->state.state = MS_WALK;
+ clif_fixmobpos(md);
+ }
+ else if(pd) {
+ pd->to_x=nx;
+ pd->to_y=ny;
+ prev_state = pd->state.state;
+ pd->state.state = MS_WALK;
+ clif_fixpetpos(pd);
+ }
+ }
+ else
+ battle_stopwalking(target,2);
+
+ dx = nx - x;
+ dy = ny - y;
+
+ if(sd) /* 画面外に出たので消去 */
+ map_foreachinmovearea(clif_pcoutsight,target->m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,0,sd);
+ else if(md)
+ map_foreachinmovearea(clif_moboutsight,target->m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,BL_PC,md);
+ else if(pd)
+ map_foreachinmovearea(clif_petoutsight,target->m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,BL_PC,pd);
+
+ if(su){
+ skill_unit_move_unit_group(su->group,target->m,dx,dy);
+ }else{
+// struct status_change *sc_data=battle_get_sc_data(target);
+ if(moveblock) map_delblock(target);
+ target->x=nx;
+ target->y=ny;
+ if(moveblock) map_addblock(target);
+/*ダンス中にエフェクトは移動しないらしい
+ if(sc_data && sc_data[SC_DANCING].timer!=-1){ //対象がダンス中なのでエフェクトも移動
+ struct skill_unit_group *sg=(struct skill_unit_group *)sc_data[SC_DANCING].val2;
+ if(sg)
+ skill_unit_move_unit_group(sg,target->m,dx,dy);
+ }
+*/
+ }
+
+ if(sd) { /* 画面内に入ってきたので表示 */
+ map_foreachinmovearea(clif_pcinsight,target->m,nx-AREA_SIZE,ny-AREA_SIZE,nx+AREA_SIZE,ny+AREA_SIZE,-dx,-dy,0,sd);
+ if(count&0x20000)
+ sd->walktimer = -1;
+ }
+ else if(md) {
+ map_foreachinmovearea(clif_mobinsight,target->m,nx-AREA_SIZE,ny-AREA_SIZE,nx+AREA_SIZE,ny+AREA_SIZE,-dx,-dy,BL_PC,md);
+ if(count&0x20000)
+ md->state.state = prev_state;
+ }
+ else if(pd) {
+ map_foreachinmovearea(clif_petinsight,target->m,nx-AREA_SIZE,ny-AREA_SIZE,nx+AREA_SIZE,ny+AREA_SIZE,-dx,-dy,BL_PC,pd);
+ if(count&0x20000)
+ pd->state.state = prev_state;
+ }
+
+ skill_unit_move(target,gettick(),(count&0xffff)+7); /* スキルユニットの判定 */
+
+ return 0;
+}
+
+
+/*
+ * =========================================================================
+ * スキル攻撃効果処理まとめ
+ * flagの説明。16進図
+ * 00XRTTff
+ * ff = magicで計算に渡される)
+ * TT = パケットのtype部分(0でデフォルト)
+ * X = パケットのスキルLv
+ * R = 予約(skill_area_subで使用する)
+ *-------------------------------------------------------------------------
+ */
+
+int skill_attack( int attack_type, struct block_list* src, struct block_list *dsrc,
+ struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag )
+{
+ struct Damage dmg;
+ struct status_change *sc_data;
+ int type,lv,damage;
+
+ rdamage = 0;
+ nullpo_retr(0, src);
+ nullpo_retr(0, dsrc);
+ nullpo_retr(0, bl);
+
+ sc_data = battle_get_sc_data(bl);
+
+//何もしない判定ここから
+ if(dsrc->m != bl->m) //対象が同じマップにいなければ何もしない
+ return 0;
+ if(src->prev == NULL || dsrc->prev == NULL || bl->prev == NULL) //prevよくわからない※
+ return 0;
+ if(src->type == BL_PC && pc_isdead((struct map_session_data *)src)) //術者?がPCですでに死んでいたら何もしない
+ return 0;
+ if(dsrc->type == BL_PC && pc_isdead((struct map_session_data *)dsrc)) //術者?がPCですでに死んでいたら何もしない
+ return 0;
+ if(bl->type == BL_PC && pc_isdead((struct map_session_data *)bl)) //対象がPCですでに死んでいたら何もしない
+ return 0;
+ if(bl->type == BL_PC && skillnotok(skillid, (struct map_session_data *) bl))
+ return 0; // [MouseJstr]
+ if(sc_data && sc_data[SC_HIDING].timer != -1) { //ハイディング状態で
+ if(skill_get_pl(skillid) != 2) //スキルの属性が地属性でなければ何もしない
+ return 0;
+ }
+ if(sc_data && sc_data[SC_TRICKDEAD].timer != -1) //死んだふり中は何もしない
+ return 0;
+ if(skillid == WZ_STORMGUST) { //使用スキルがストームガストで
+ if(sc_data && sc_data[SC_FREEZE].timer != -1) //凍結状態なら何もしない
+ return 0;
+ }
+ if(skillid == WZ_FROSTNOVA && dsrc->x == bl->x && dsrc->y == bl->y) //使用スキルがフロストノヴァで、dsrcとblが同じ場所なら何もしない
+ return 0;
+ if(src->type == BL_PC && ((struct map_session_data *)src)->chatID) //術者がPCでチャット中なら何もしない
+ return 0;
+ if(dsrc->type == BL_PC && ((struct map_session_data *)dsrc)->chatID) //術者がPCでチャット中なら何もしない
+ return 0;
+ if(src->type == BL_PC && bl && mob_gvmobcheck(((struct map_session_data *)src),bl)==0)
+ return 0;
+
+//何もしない判定ここまで
+
+ type=-1;
+ lv=(flag>>20)&0xf;
+ dmg=battle_calc_attack(attack_type,src,bl,skillid,skilllv,flag&0xff ); //ダメージ計算
+
+//マジックロッド処理ここから
+ if(attack_type&BF_MAGIC && sc_data && sc_data[SC_MAGICROD].timer != -1 && src == dsrc) { //魔法攻撃でマジックロッド状態でsrc=dsrcなら
+ dmg.damage = dmg.damage2 = 0; //ダメージ0
+ if(bl->type == BL_PC) { //対象がPCの場合
+ int sp = skill_get_sp(skillid,skilllv); //使用されたスキルのSPを吸収
+ sp = sp * sc_data[SC_MAGICROD].val2 / 100; //吸収率計算
+ if(skillid == WZ_WATERBALL && skilllv > 1) //ウォーターボールLv1以上
+ sp = sp/((skilllv|1)*(skilllv|1)); //さらに計算?
+ if(sp > 0x7fff) sp = 0x7fff; //SP多すぎの場合は理論最大値
+ else if(sp < 1) sp = 1; //1以下の場合は1
+ if(((struct map_session_data *)bl)->status.sp + sp > ((struct map_session_data *)bl)->status.max_sp) { //回復SP+現在のSPがMSPより大きい場合
+ sp = ((struct map_session_data *)bl)->status.max_sp - ((struct map_session_data *)bl)->status.sp; //SPをMSP-現在SPにする
+ ((struct map_session_data *)bl)->status.sp = ((struct map_session_data *)bl)->status.max_sp; //現在のSPにMSPを代入
+ }
+ else //回復SP+現在のSPがMSPより小さい場合は回復SPを加算
+ ((struct map_session_data *)bl)->status.sp += sp;
+ clif_heal(((struct map_session_data *)bl)->fd,SP_SP,sp); //SP回復エフェクトの表示
+ ((struct map_session_data *)bl)->canact_tick = tick + skill_delayfix(bl, skill_get_delay(SA_MAGICROD,sc_data[SC_MAGICROD].val1)); //
+ }
+ clif_skill_nodamage(bl,bl,SA_MAGICROD,sc_data[SC_MAGICROD].val1,1); //マジックロッドエフェクトを表示
+ }
+//マジックロッド処理ここまで
+
+ if(src->type==BL_PET) { // [Valaris]
+ dmg.damage=battle_attr_fix(skilllv, skill_get_pl(skillid), battle_get_element(bl) );
+ dmg.damage2=0;
+ }
+
+ damage = dmg.damage + dmg.damage2;
+
+ if(lv==15)
+ lv=-1;
+
+ if( flag&0xff00 )
+ type=(flag&0xff00)>>8;
+
+ if(damage <= 0 || damage < dmg.div_) //吹き飛ばし判定?※
+ dmg.blewcount = 0;
+
+ if(skillid == CR_GRANDCROSS) {//グランドクロス
+ if(battle_config.gx_disptype) dsrc = src; // 敵ダメージ白文字表示
+ if( src == bl) type = 4; // 反動はダメージモーションなし
+ }
+
+//使用者がPCの場合の処理ここから
+ if(src->type == BL_PC) {
+ struct map_session_data *sd = (struct map_session_data *)src;
+ nullpo_retr(0, sd);
+//連打掌(MO_CHAINCOMBO)ここから
+ if(skillid == MO_CHAINCOMBO) {
+ int delay = 1000 - 4 * battle_get_agi(src) - 2 * battle_get_dex(src); //基本ディレイの計算
+ if(damage < battle_get_hp(bl)) { //ダメージが対象のHPより小さい場合
+ if(pc_checkskill(sd, MO_COMBOFINISH) > 0 && sd->spiritball > 0) //猛龍拳(MO_COMBOFINISH)取得&気球保持時は+300ms
+ delay += 300 * battle_config.combo_delay_rate /100; //追加ディレイをconfにより調整
+
+ skill_status_change_start(src,SC_COMBO,MO_CHAINCOMBO,skilllv,0,0,delay,0); //コンボ状態に
+ }
+ sd->attackabletime = sd->canmove_tick = tick + delay;
+ clif_combo_delay(src,delay); //コンボディレイパケットの送信
+ }
+//連打掌(MO_CHAINCOMBO)ここまで
+//猛龍拳(MO_COMBOFINISH)ここから
+ else if(skillid == MO_COMBOFINISH) {
+ int delay = 700 - 4 * battle_get_agi(src) - 2 * battle_get_dex(src);
+ if(damage < battle_get_hp(bl)) {
+ //阿修羅覇凰拳(MO_EXTREMITYFIST)取得&気球4個保持&爆裂波動(MO_EXPLOSIONSPIRITS)状態時は+300ms
+ //伏虎拳(CH_TIGERFIST)取得時も+300ms
+ if((pc_checkskill(sd, MO_EXTREMITYFIST) > 0 && sd->spiritball >= 4 && sd->sc_data[SC_EXPLOSIONSPIRITS].timer != -1) ||
+ (pc_checkskill(sd, CH_TIGERFIST) > 0 && sd->spiritball > 0) ||
+ (pc_checkskill(sd, CH_CHAINCRUSH) > 0 && sd->spiritball > 1))
+ delay += 300 * battle_config.combo_delay_rate /100; //追加ディレイをconfにより調整
+
+ skill_status_change_start(src,SC_COMBO,MO_COMBOFINISH,skilllv,0,0,delay,0); //コンボ状態に
+ }
+ sd->attackabletime = sd->canmove_tick = tick + delay;
+ clif_combo_delay(src,delay); //コンボディレイパケットの送信
+ }
+//猛龍拳(MO_COMBOFINISH)ここまで
+//伏虎拳(CH_TIGERFIST)ここから
+ else if(skillid == CH_TIGERFIST) {
+ int delay = 1000 - 4 * battle_get_agi(src) - 2 * battle_get_dex(src);
+ if(damage < battle_get_hp(bl)) {
+ if(pc_checkskill(sd, CH_CHAINCRUSH) > 0) //連柱崩撃(CH_CHAINCRUSH)取得時は+300ms
+ delay += 300 * battle_config.combo_delay_rate /100; //追加ディレイをconfにより調整
+
+ skill_status_change_start(src,SC_COMBO,CH_TIGERFIST,skilllv,0,0,delay,0); //コンボ状態に
+ }
+ sd->attackabletime = sd->canmove_tick = tick + delay;
+ clif_combo_delay(src,delay); //コンボディレイパケットの送信
+ }
+//伏虎拳(CH_TIGERFIST)ここまで
+//連柱崩撃(CH_CHAINCRUSH)ここから
+ else if(skillid == CH_CHAINCRUSH) {
+ int delay = 1000 - 4 * battle_get_agi(src) - 2 * battle_get_dex(src);
+ if(damage < battle_get_hp(bl)) {
+ //阿修羅覇凰拳(MO_EXTREMITYFIST)取得&気球4個保持&爆裂波動(MO_EXPLOSIONSPIRITS)状態時は+300ms
+ if(pc_checkskill(sd, MO_EXTREMITYFIST) > 0 && sd->spiritball >= 4 && sd->sc_data[SC_EXPLOSIONSPIRITS].timer != -1)
+ delay += 300 * battle_config.combo_delay_rate /100; //追加ディレイをconfにより調整
+
+ skill_status_change_start(src,SC_COMBO,CH_CHAINCRUSH,skilllv,0,0,delay,0); //コンボ状態に
+ }
+ sd->attackabletime = sd->canmove_tick = tick + delay;
+ clif_combo_delay(src,delay); //コンボディレイパケットの送信
+ }
+//連柱崩撃(CH_CHAINCRUSH)ここまで
+ }
+//使用者がPCの場合の処理ここまで
+//武器スキル?ここから
+ //AppleGirl Was Here
+ if(attack_type&BF_MAGIC && damage > 0 && src != bl && src == dsrc) { //Blah Blah
+ if(bl->type == BL_PC) { //Blah Blah
+ struct map_session_data *tsd = (struct map_session_data *)bl;
+ if(tsd->magic_damage_return > 0) { //More Blah
+ rdamage += damage * tsd->magic_damage_return / 100;
+ if(rdamage < 1) rdamage = 1;
+ }
+ }
+ }
+ //Stop Here
+ if(attack_type&BF_WEAPON && damage > 0 && src != bl && src == dsrc) { //武器スキル&ダメージあり&使用者と対象者が違う&src=dsrc
+ if(dmg.flag&BF_SHORT) { //近距離攻撃時?※
+ if(bl->type == BL_PC) { //対象がPCの時
+ struct map_session_data *tsd = (struct map_session_data *)bl;
+ nullpo_retr(0, tsd);
+ if(tsd->short_weapon_damage_return > 0) { //近距離攻撃跳ね返し?※
+ rdamage += damage * tsd->short_weapon_damage_return / 100;
+ if(rdamage < 1) rdamage = 1;
+ }
+ }
+ if(sc_data && sc_data[SC_REFLECTSHIELD].timer != -1) { //リフレクトシールド時
+ rdamage += damage * sc_data[SC_REFLECTSHIELD].val2 / 100; //跳ね返し計算
+ if(rdamage < 1) rdamage = 1;
+ }
+ }
+ else if(dmg.flag&BF_LONG) { //遠距離攻撃時?※
+ if(bl->type == BL_PC) { //対象がPCの時
+ struct map_session_data *tsd = (struct map_session_data *)bl;
+ nullpo_retr(0, tsd);
+ if(tsd->long_weapon_damage_return > 0) { //遠距離攻撃跳ね返し?※
+ rdamage += damage * tsd->long_weapon_damage_return / 100;
+ if(rdamage < 1) rdamage = 1;
+ }
+ }
+ }
+ if(rdamage > 0)
+ clif_damage(src,src,tick, dmg.amotion,0,rdamage,1,4,0);
+ }
+//武器スキル?ここまで
+
+ switch(skillid){
+ case WZ_SIGHTRASHER:
+ clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, skillid, (lv!=0)?lv:skilllv, 5);
+ break;
+ case AS_SPLASHER:
+ clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, skillid, -1, 5);
+ break;
+ case NPC_SELFDESTRUCTION:
+ case NPC_SELFDESTRUCTION2:
+ break;
+ default:
+ clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, skillid, (lv!=0)?lv:skilllv, (skillid==0)? 5:type );
+ }
+ if(dmg.blewcount > 0 && !map[src->m].flag.gvg) { /* 吹き飛ばし処理とそのパケット */
+ if(skillid == WZ_SIGHTRASHER)
+ skill_blown(src,bl,dmg.blewcount);
+ else
+ skill_blown(dsrc,bl,dmg.blewcount);
+ if(bl->type == BL_MOB)
+ clif_fixmobpos((struct mob_data *)bl);
+ else if(bl->type == BL_PET)
+ clif_fixpetpos((struct pet_data *)bl);
+ else
+ clif_fixpos(bl);
+ }
+
+ map_freeblock_lock();
+ /* 実際にダメージ処理を行う */
+ if(skillid != KN_BOWLINGBASH || flag)
+ battle_damage(src,bl,damage,0);
+ if(skillid == RG_INTIMIDATE && damage > 0 && !(battle_get_mode(bl)&0x20) && !map[src->m].flag.gvg ) {
+ int s_lv = battle_get_lv(src),t_lv = battle_get_lv(bl);
+ int rate = 50 + skilllv * 5;
+ rate = rate + (s_lv - t_lv);
+ if(rand()%100 < rate)
+ skill_addtimerskill(src,tick + 800,bl->id,0,0,skillid,skilllv,0,flag);
+ }
+ if(damage > 0 && dmg.flag&BF_SKILL && bl->type==BL_PC && pc_checkskill((struct map_session_data *)bl,RG_PLAGIARISM)){
+ struct map_session_data *tsd = (struct map_session_data *)bl;
+ nullpo_retr(0, tsd);
+ if(!tsd->status.skill[skillid].id && !tsd->status.skill[skillid].id
+ && !(skillid > NPC_PIERCINGATT && skillid < NPC_SUMMONMONSTER) ){
+ //既に盗んでいるスキルがあれば該当スキルを消す
+ if (tsd->cloneskill_id && tsd->cloneskill_lv && tsd->status.skill[tsd->cloneskill_id].flag==13){
+ tsd->status.skill[tsd->cloneskill_id].id=0;
+ tsd->status.skill[tsd->cloneskill_id].lv=0;
+ tsd->status.skill[tsd->cloneskill_id].flag=0;
+ }
+ tsd->cloneskill_id=skillid;
+ tsd->cloneskill_lv=skilllv;
+ tsd->status.skill[skillid].id=skillid;
+ tsd->status.skill[skillid].lv=(pc_checkskill(tsd,RG_PLAGIARISM) > skill_get_max(skillid))?
+ skill_get_max(skillid):pc_checkskill(tsd,RG_PLAGIARISM);
+ tsd->status.skill[skillid].flag=13;//cloneskill flag
+ clif_skillinfoblock(tsd);
+ }
+ }
+ /* ダメージがあるなら追加効果判定 */
+ if(bl->prev != NULL){
+ struct map_session_data *sd = (struct map_session_data *)bl;
+ nullpo_retr(0, sd);
+ if( bl->type != BL_PC || (sd && !pc_isdead(sd)) ) {
+ if(damage > 0)
+ skill_additional_effect(src,bl,skillid,skilllv,attack_type,tick);
+ if(bl->type==BL_MOB && src!=bl) /* スキル使用条件のMOBスキル */
+ {
+ struct mob_data *md=(struct mob_data *)bl;
+ nullpo_retr(0, md);
+ if(battle_config.mob_changetarget_byskill == 1)
+ {
+ int target;
+ target=md->target_id;
+ if(src->type == BL_PC)
+ md->target_id=src->id;
+ mobskill_use(md,tick,MSC_SKILLUSED|(skillid<<16));
+ md->target_id=target;
+ }
+ else
+ mobskill_use(md,tick,MSC_SKILLUSED|(skillid<<16));
+ }
+ }
+ }
+
+ if(src->type == BL_PC && dmg.flag&BF_WEAPON && src != bl && src == dsrc && damage > 0) {
+ struct map_session_data *sd = (struct map_session_data *)src;
+ int hp = 0,sp = 0;
+ nullpo_retr(0, sd);
+ if(sd->hp_drain_rate && sd->hp_drain_per > 0 && dmg.damage > 0 && rand()%100 < sd->hp_drain_rate) {
+ hp += (dmg.damage * sd->hp_drain_per)/100;
+ if(sd->hp_drain_rate > 0 && hp < 1) hp = 1;
+ else if(sd->hp_drain_rate < 0 && hp > -1) hp = -1;
+ }
+ if(sd->hp_drain_rate_ && sd->hp_drain_per_ > 0 && dmg.damage2 > 0 && rand()%100 < sd->hp_drain_rate_) {
+ hp += (dmg.damage2 * sd->hp_drain_per_)/100;
+ if(sd->hp_drain_rate_ > 0 && hp < 1) hp = 1;
+ else if(sd->hp_drain_rate_ < 0 && hp > -1) hp = -1;
+ }
+ if(sd->sp_drain_rate > 0 && sd->sp_drain_per > 0 && dmg.damage > 0 && rand()%100 < sd->sp_drain_rate) {
+ sp += (dmg.damage * sd->sp_drain_per)/100;
+ if(sd->sp_drain_rate > 0 && sp < 1) sp = 1;
+ else if(sd->sp_drain_rate < 0 && sp > -1) sp = -1;
+ }
+ if(sd->sp_drain_rate_ > 0 && sd->sp_drain_per_ > 0 && dmg.damage2 > 0 && rand()%100 < sd->sp_drain_rate_) {
+ sp += (dmg.damage2 * sd->sp_drain_per_)/100;
+ if(sd->sp_drain_rate_ > 0 && sp < 1) sp = 1;
+ else if(sd->sp_drain_rate_ < 0 && sp > -1) sp = -1;
+ }
+ if(hp || sp) pc_heal(sd,hp,sp);
+ }
+
+ if((skillid != KN_BOWLINGBASH || flag) && rdamage > 0)
+ battle_damage(bl,src,rdamage,0);
+
+ if(attack_type&BF_WEAPON && sc_data && sc_data[SC_AUTOCOUNTER].timer != -1 && sc_data[SC_AUTOCOUNTER].val4 > 0) {
+ if(sc_data[SC_AUTOCOUNTER].val3 == dsrc->id)
+ battle_weapon_attack(bl,dsrc,tick,0x8000|sc_data[SC_AUTOCOUNTER].val1);
+ skill_status_change_end(bl,SC_AUTOCOUNTER,-1);
+ }
+
+ map_freeblock_unlock();
+
+ return (dmg.damage+dmg.damage2); /* 与ダメを返す */
+}
+
+/*==========================================
+ * スキル範囲攻撃用(map_foreachinareaから呼ばれる)
+ * flagについて:16進図を確認
+ * MSB <- 00fTffff ->LSB
+ * T =ターゲット選択用(BCT_*)
+ * ffff=自由に使用可能
+ * 0 =予約。0に固定
+ *------------------------------------------
+ */
+static int skill_area_temp[8]; /* 一時変数。必要なら使う。 */
+typedef int (*SkillFunc)(struct block_list *,struct block_list *,int,int,unsigned int,int);
+int skill_area_sub( struct block_list *bl,va_list ap )
+{
+ struct block_list *src;
+ int skill_id,skill_lv,flag;
+ unsigned int tick;
+ SkillFunc func;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+
+ if(bl->type!=BL_PC && bl->type!=BL_MOB && bl->type!=BL_SKILL)
+ return 0;
+
+ src=va_arg(ap,struct block_list *); //ここではsrcの値を参照していないのでNULLチェックはしない
+ skill_id=va_arg(ap,int);
+ skill_lv=va_arg(ap,int);
+ tick=va_arg(ap,unsigned int);
+ flag=va_arg(ap,int);
+ func=va_arg(ap,SkillFunc);
+
+ if(battle_check_target(src,bl,flag) > 0)
+ func(src,bl,skill_id,skill_lv,tick,flag);
+ return 0;
+}
+
+static int skill_check_unit_range_sub( struct block_list *bl,va_list ap )
+{
+ struct skill_unit *unit;
+ int *c,x,y,range,sx[4],sy[4];
+ int t_range,tx[4],ty[4];
+ int i,r_flag,skillid;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, unit = (struct skill_unit *)bl);
+ nullpo_retr(0, c = va_arg(ap,int *));
+
+ if(bl->prev == NULL || bl->type != BL_SKILL)
+ return 0;
+
+ if(!unit->alive)
+ return 0;
+
+ x = va_arg(ap,int);
+ y = va_arg(ap,int);
+ range = va_arg(ap,int);
+ skillid = va_arg(ap,int);
+
+ if(skillid == MG_SAFETYWALL || skillid == AL_PNEUMA) {
+ if(unit->group->unit_id != 0x7e && unit->group->unit_id != 0x85)
+ return 0;
+ }
+ else if(skillid == AL_WARP) {
+ if((unit->group->unit_id < 0x8f || unit->group->unit_id > 0x99) && unit->group->unit_id != 0x92)
+ return 0;
+ }
+ else if((skillid >= HT_SKIDTRAP && skillid <= HT_CLAYMORETRAP) || skillid == HT_TALKIEBOX) {
+ if((unit->group->unit_id < 0x8f || unit->group->unit_id > 0x99) && unit->group->unit_id != 0x92)
+ return 0;
+ }
+ else if(skillid == WZ_FIREPILLAR) {
+ if(unit->group->unit_id != 0x87)
+ return 0;
+ }
+ else return 0;
+ t_range=(unit->range!=0)? unit->range:unit->group->range;
+ tx[0] = tx[3] = unit->bl.x - t_range;
+ tx[1] = tx[2] = unit->bl.x + t_range;
+ ty[0] = ty[1] = unit->bl.y - t_range;
+ ty[2] = ty[3] = unit->bl.y + t_range;
+ sx[0] = sx[3] = x - range;
+ sx[1] = sx[2] = x + range;
+ sy[0] = sy[1] = y - range;
+ sy[2] = sy[3] = y + range;
+ for(i=r_flag=0;i<4;i++) {
+ if(sx[i] >= tx[0] && sx[i] <= tx[1] && sy[i] >= ty[0] && sy[i] <= ty[2]) {
+ r_flag = 1;
+ break;
+ }
+ if(tx[i] >= sx[0] && tx[i] <= sx[1] && ty[i] >= sy[0] && ty[i] <= sy[2]) {
+ r_flag = 1;
+ break;
+ }
+ }
+ if(r_flag) (*c)++;
+
+ return 0;
+}
+
+int skill_check_unit_range(int m,int x,int y,int range,int skillid)
+{
+ int c = 0;
+
+ map_foreachinarea(skill_check_unit_range_sub,m,x-10,y-10,x+10,y+10,BL_SKILL,&c,x,y,range,skillid);
+
+ return c;
+}
+
+static int skill_check_unit_range2_sub( struct block_list *bl,va_list ap )
+{
+ int *c;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, c = va_arg(ap,int *));
+
+ if(bl->prev == NULL || (bl->type != BL_PC && bl->type != BL_MOB))
+ return 0;
+
+ if(bl->type == BL_PC && pc_isdead((struct map_session_data *)bl))
+ return 0;
+
+ (*c)++;
+
+ return 0;
+}
+
+int skill_check_unit_range2(int m,int x,int y,int range)
+{
+ int c = 0;
+
+ map_foreachinarea(skill_check_unit_range2_sub,m,x-range,y-range,x+range,y+range,0,&c);
+
+ return c;
+}
+
+/*=========================================================================
+ * 範囲スキル使用処理小分けここから
+ */
+/* 対象の数をカウントする。(skill_area_temp[0]を初期化しておくこと) */
+int skill_area_sub_count(struct block_list *src,struct block_list *target,int skillid,int skilllv,unsigned int tick,int flag)
+{
+ if(skill_area_temp[0] < 0xffff)
+ skill_area_temp[0]++;
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+static int skill_timerskill(int tid, unsigned int tick, int id,int data )
+{
+ struct map_session_data *sd = NULL;
+ struct mob_data *md = NULL;
+ struct pet_data *pd = NULL;
+ struct block_list *src = map_id2bl(id),*target;
+ struct skill_timerskill *skl = NULL;
+ int range;
+
+ nullpo_retr(0, src);
+
+ if(src->prev == NULL)
+ return 0;
+
+ if(src->type == BL_PC) {
+ nullpo_retr(0, sd = (struct map_session_data *)src);
+ skl = &sd->skilltimerskill[data];
+ }
+ else if(src->type == BL_MOB) {
+ nullpo_retr(0, md = (struct mob_data *)src);
+ skl = &md->skilltimerskill[data];
+ }
+ else if(src->type == BL_PET) { // [Valaris]
+ nullpo_retr(0, pd = (struct pet_data *)src);
+ skl = &pd->skilltimerskill[data];
+ }
+
+ else
+ return 0;
+
+ nullpo_retr(0, skl);
+
+ skl->timer = -1;
+ if(skl->target_id) {
+ struct block_list tbl;
+ target = map_id2bl(skl->target_id);
+ if(skl->skill_id == RG_INTIMIDATE) {
+ if(target == NULL) {
+ target = &tbl; //初期化してないのにアドレス突っ込んでいいのかな?
+ target->type = BL_NUL;
+ target->m = src->m;
+ target->prev = target->next = NULL;
+ }
+ }
+ if(target == NULL)
+ return 0;
+ if(target->prev == NULL && skl->skill_id != RG_INTIMIDATE)
+ return 0;
+ if(src->m != target->m)
+ return 0;
+ if(sd && pc_isdead(sd))
+ return 0;
+ if(target->type == BL_PC && pc_isdead((struct map_session_data *)target) && skl->skill_id != RG_INTIMIDATE)
+ return 0;
+
+ switch(skl->skill_id) {
+ case TF_BACKSLIDING:
+ clif_skill_nodamage(src,src,skl->skill_id,skl->skill_lv,1);
+ break;
+ case RG_INTIMIDATE:
+ if(sd && !map[src->m].flag.noteleport) {
+ int x,y,i,j,c;
+ pc_randomwarp(sd,3);
+ for(i=0;i<16;i++) {
+ j = rand()%8;
+ x = sd->bl.x + dirx[j];
+ y = sd->bl.y + diry[j];
+ if((c=map_getcell(sd->bl.m,x,y)) != 1 && c != 5)
+ break;
+ }
+ if(i >= 16) {
+ x = sd->bl.x;
+ y = sd->bl.y;
+ }
+ if(target->prev != NULL) {
+ if(target->type == BL_PC && !pc_isdead((struct map_session_data *)target))
+ pc_setpos((struct map_session_data *)target,map[sd->bl.m].name,x,y,3);
+ else if(target->type == BL_MOB)
+ mob_warp((struct mob_data *)target,-1,x,y,3);
+ }
+ }
+ else if(md && !map[src->m].flag.monster_noteleport) {
+ int x,y,i,j,c;
+ mob_warp(md,-1,-1,-1,3);
+ for(i=0;i<16;i++) {
+ j = rand()%8;
+ x = md->bl.x + dirx[j];
+ y = md->bl.y + diry[j];
+ if((c=map_getcell(md->bl.m,x,y)) != 1 && c != 5)
+ break;
+ }
+ if(i >= 16) {
+ x = md->bl.x;
+ y = md->bl.y;
+ }
+ if(target->prev != NULL) {
+ if(target->type == BL_PC && !pc_isdead((struct map_session_data *)target))
+ pc_setpos((struct map_session_data *)target,map[md->bl.m].name,x,y,3);
+ else if(target->type == BL_MOB)
+ mob_warp((struct mob_data *)target,-1,x,y,3);
+ }
+ }
+ break;
+
+ case BA_FROSTJOKE: /* 寒いジョーク */
+ case DC_SCREAM: /* スクリーム */
+ range=15; //視界全体
+ map_foreachinarea(skill_frostjoke_scream,src->m,src->x-range,src->y-range,
+ src->x+range,src->y+range,0,src,skl->skill_id,skl->skill_lv,tick);
+ break;
+
+ default:
+ skill_attack(skl->type,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag);
+ break;
+ }
+ }
+ else {
+ if(src->m != skl->map)
+ return 0;
+ switch(skl->skill_id) {
+ case WZ_METEOR:
+ if(skl->type >= 0) {
+ skill_unitsetting(src,skl->skill_id,skl->skill_lv,skl->type>>16,skl->type&0xFFFF,0);
+ clif_skill_poseffect(src,skl->skill_id,skl->skill_lv,skl->x,skl->y,tick);
+ }
+ else
+ skill_unitsetting(src,skl->skill_id,skl->skill_lv,skl->x,skl->y,0);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int skill_addtimerskill(struct block_list *src,unsigned int tick,int target,int x,int y,int skill_id,int skill_lv,int type,int flag)
+{
+ int i;
+
+ nullpo_retr(1, src);
+
+ if(src->type == BL_PC) {
+ struct map_session_data *sd = (struct map_session_data *)src;
+ nullpo_retr(1, sd);
+ for(i=0;i<MAX_SKILLTIMERSKILL;i++) {
+ if(sd->skilltimerskill[i].timer == -1) {
+ sd->skilltimerskill[i].timer = add_timer(tick, skill_timerskill, src->id, i);
+ sd->skilltimerskill[i].src_id = src->id;
+ sd->skilltimerskill[i].target_id = target;
+ sd->skilltimerskill[i].skill_id = skill_id;
+ sd->skilltimerskill[i].skill_lv = skill_lv;
+ sd->skilltimerskill[i].map = src->m;
+ sd->skilltimerskill[i].x = x;
+ sd->skilltimerskill[i].y = y;
+ sd->skilltimerskill[i].type = type;
+ sd->skilltimerskill[i].flag = flag;
+
+ return 0;
+ }
+ }
+ return 1;
+ }
+ else if(src->type == BL_MOB) {
+ struct mob_data *md = (struct mob_data *)src;
+ nullpo_retr(1, md);
+ for(i=0;i<MAX_MOBSKILLTIMERSKILL;i++) {
+ if(md->skilltimerskill[i].timer == -1) {
+ md->skilltimerskill[i].timer = add_timer(tick, skill_timerskill, src->id, i);
+ md->skilltimerskill[i].src_id = src->id;
+ md->skilltimerskill[i].target_id = target;
+ md->skilltimerskill[i].skill_id = skill_id;
+ md->skilltimerskill[i].skill_lv = skill_lv;
+ md->skilltimerskill[i].map = src->m;
+ md->skilltimerskill[i].x = x;
+ md->skilltimerskill[i].y = y;
+ md->skilltimerskill[i].type = type;
+ md->skilltimerskill[i].flag = flag;
+
+ return 0;
+ }
+ }
+ return 1;
+ }
+ else if(src->type == BL_PET) { // [Valaris]
+ struct pet_data *pd = (struct pet_data *)src;
+ nullpo_retr(1, pd);
+ for(i=0;i<MAX_MOBSKILLTIMERSKILL;i++) {
+ if(pd->skilltimerskill[i].timer == -1) {
+ pd->skilltimerskill[i].timer = add_timer(tick, skill_timerskill, src->id, i);
+ pd->skilltimerskill[i].src_id = src->id;
+ pd->skilltimerskill[i].target_id = target;
+ pd->skilltimerskill[i].skill_id = skill_id;
+ pd->skilltimerskill[i].skill_lv = skill_lv;
+ pd->skilltimerskill[i].map = src->m;
+ pd->skilltimerskill[i].x = x;
+ pd->skilltimerskill[i].y = y;
+ pd->skilltimerskill[i].type = type;
+ pd->skilltimerskill[i].flag = flag;
+
+ return 0;
+ }
+ }
+ return 1;
+ }
+ return 1;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int skill_cleartimerskill(struct block_list *src)
+{
+ int i;
+
+ nullpo_retr(0, src);
+
+ if(src->type == BL_PC) {
+ struct map_session_data *sd = (struct map_session_data *)src;
+ nullpo_retr(0, sd);
+ for(i=0;i<MAX_SKILLTIMERSKILL;i++) {
+ if(sd->skilltimerskill[i].timer != -1) {
+ delete_timer(sd->skilltimerskill[i].timer, skill_timerskill);
+ sd->skilltimerskill[i].timer = -1;
+ }
+ }
+ }
+ else if(src->type == BL_MOB) {
+ struct mob_data *md = (struct mob_data *)src;
+ nullpo_retr(0, md);
+ for(i=0;i<MAX_MOBSKILLTIMERSKILL;i++) {
+ if(md->skilltimerskill[i].timer != -1) {
+ delete_timer(md->skilltimerskill[i].timer, skill_timerskill);
+ md->skilltimerskill[i].timer = -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* 範囲スキル使用処理小分けここまで
+ * -------------------------------------------------------------------------
+ */
+
+/*==========================================
+ * スキル使用(詠唱完了、ID指定攻撃系)
+ * (スパゲッティに向けて1歩前進!(ダメポ))
+ *------------------------------------------
+ */
+int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag )
+{
+ struct map_session_data *sd=NULL;
+ int i;
+
+ nullpo_retr(1, src);
+ nullpo_retr(1, bl);
+
+ if(src->type==BL_PC)
+ sd=(struct map_session_data *)src;
+ if(sd && pc_isdead(sd))
+ return 1;
+
+ if((skillid == WZ_SIGHTRASHER || skillid == CR_GRANDCROSS) && src != bl)
+ bl = src;
+ if(bl->prev == NULL)
+ return 1;
+ if(bl->type == BL_PC && pc_isdead((struct map_session_data *)bl))
+ return 1;
+ map_freeblock_lock();
+ switch(skillid)
+ {
+ /* 武器攻撃系スキル */
+ case SM_BASH: /* バッシュ */
+ case MC_MAMMONITE: /* メマーナイト */
+ case AC_DOUBLE: /* ダブルストレイフィング */
+ case AS_SONICBLOW: /* ソニックブロー */
+ case KN_PIERCE: /* ピアース */
+ case KN_SPEARBOOMERANG: /* スピアブーメラン */
+ case TF_POISON: /* インベナム */
+ case TF_SPRINKLESAND: /* 砂まき */
+ case AC_CHARGEARROW: /* チャージアロー */
+ case KN_SPEARSTAB: /* スピアスタブ */
+ case RG_RAID: /* サプライズアタック */
+ case RG_INTIMIDATE: /* インティミデイト */
+ case BA_MUSICALSTRIKE: /* ミュージカルストライク */
+ case DC_THROWARROW: /* 矢撃ち */
+ case BA_DISSONANCE: /* 不協和音 */
+ case CR_HOLYCROSS: /* ホーリークロス */
+ case CR_SHIELDCHARGE:
+ case CR_SHIELDBOOMERANG:
+
+ /* 以下MOB専用 */
+ /* 単体攻撃、SP減少攻撃、遠距離攻撃、防御無視攻撃、多段攻撃 */
+ case NPC_PIERCINGATT:
+ case NPC_MENTALBREAKER:
+ case NPC_RANGEATTACK:
+ case NPC_CRITICALSLASH:
+ case NPC_COMBOATTACK:
+ /* 必中攻撃、毒攻撃、暗黒攻撃、沈黙攻撃、スタン攻撃 */
+ case NPC_GUIDEDATTACK:
+ case NPC_POISON:
+ case NPC_BLINDATTACK:
+ case NPC_SILENCEATTACK:
+ case NPC_STUNATTACK:
+ /* 石化攻撃、呪い攻撃、睡眠攻撃、ランダムATK攻撃 */
+ case NPC_PETRIFYATTACK:
+ case NPC_CURSEATTACK:
+ case NPC_SLEEPATTACK:
+ case NPC_RANDOMATTACK:
+ /* 水属性攻撃、地属性攻撃、火属性攻撃、風属性攻撃 */
+ case NPC_WATERATTACK:
+ case NPC_GROUNDATTACK:
+ case NPC_FIREATTACK:
+ case NPC_WINDATTACK:
+ /* 毒属性攻撃、聖属性攻撃、闇属性攻撃、念属性攻撃、SP減少攻撃 */
+ case NPC_POISONATTACK:
+ case NPC_HOLYATTACK:
+ case NPC_DARKNESSATTACK:
+ case NPC_TELEKINESISATTACK:
+ case LK_AURABLADE: /* オーラブレード */
+ case LK_SPIRALPIERCE: /* スパイラルピアース */
+ case LK_HEADCRUSH: /* ヘッドクラッシュ */
+ case LK_JOINTBEAT: /* ジョイントビート */
+ case PA_PRESSURE: /* プレッシャー */
+ case PA_SACRIFICE: /* サクリファイス */
+ case SN_SHARPSHOOTING: /* シャープシューティング */
+ case CG_ARROWVULCAN: /* アローバルカン */
+ case ASC_BREAKER: /* ソウルブレーカー */
+ case HW_MAGICCRASHER: /* マジッククラッシャー */
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ break;
+ case NPC_DARKBREATH:
+ clif_emotion(src,7);
+ skill_attack(BF_MISC,src,src,bl,skillid,skilllv,tick,flag);
+ break;
+ case MO_INVESTIGATE: /* 発勁 */
+ {
+ struct status_change *sc_data = battle_get_sc_data(src);
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ if(sc_data[SC_BLADESTOP].timer != -1)
+ skill_status_change_end(src,SC_BLADESTOP,-1);
+ }
+ break;
+ case SN_FALCONASSAULT: /* ファルコンアサルト */
+ skill_attack(BF_MISC,src,src,bl,skillid,skilllv,tick,flag);
+ break;
+ case KN_BRANDISHSPEAR: /* ブランディッシュスピア */
+ {
+ struct mob_data *md = (struct mob_data *)bl;
+ nullpo_retr(1, md);
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ if(md->hp > 0){
+ skill_blown(src,bl,skill_get_blewcount(skillid,skilllv));
+ if(bl->type == BL_MOB)
+ clif_fixmobpos((struct mob_data *)bl);
+ else if(bl->type == BL_PET)
+ clif_fixpetpos((struct pet_data *)bl);
+ else
+ clif_fixpos(bl);
+ }
+ }
+ break;
+ case RG_BACKSTAP: /* バックスタブ */
+ {
+ int dir = map_calc_dir(src,bl->x,bl->y),t_dir = battle_get_dir(bl);
+ int dist = distance(src->x,src->y,bl->x,bl->y);
+ if((dist > 0 && !map_check_dir(dir,t_dir)) || bl->type == BL_SKILL) {
+ struct status_change *sc_data = battle_get_sc_data(src);
+ if(sc_data && sc_data[SC_HIDING].timer != -1)
+ skill_status_change_end(src, SC_HIDING, -1); // ハイディング解除
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ }
+ else if(src->type == BL_PC)
+ clif_skill_fail(sd,sd->skillid,0,0);
+ }
+ break;
+
+ case AM_ACIDTERROR: /* アシッドテラー */
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ if(bl->type == BL_PC && rand()%100 < skill_get_time(skillid,skilllv) && battle_config.equipment_breaking)
+ pc_breakarmor((struct map_session_data *)bl);
+ break;
+ case MO_FINGEROFFENSIVE: /* 指弾 */
+ {
+ struct status_change *sc_data = battle_get_sc_data(src);
+
+ if(!battle_config.finger_offensive_type)
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ else {
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ if(sd) {
+ for(i=1;i<sd->spiritball_old;i++)
+ skill_addtimerskill(src,tick+i*200,bl->id,0,0,skillid,skilllv,BF_WEAPON,flag);
+ sd->canmove_tick = tick + (sd->spiritball_old-1)*200;
+ }
+ }
+ if(sc_data && sc_data[SC_BLADESTOP].timer != -1)
+ skill_status_change_end(src,SC_BLADESTOP,-1);
+ }
+ break;
+ case MO_CHAINCOMBO: /* 連打掌 */
+ {
+ struct status_change *sc_data = battle_get_sc_data(src);
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ if(sc_data && sc_data[SC_BLADESTOP].timer != -1)
+ skill_status_change_end(src,SC_BLADESTOP,-1);
+ }
+ break;
+ case MO_COMBOFINISH: /* 猛龍拳 */
+ case CH_TIGERFIST: /* 伏虎拳 */
+ case CH_CHAINCRUSH: /* 連柱崩撃 */
+ case CH_PALMSTRIKE: /* 猛虎硬派山 */
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ break;
+ case MO_EXTREMITYFIST: /* 阿修羅覇鳳拳 */
+ {
+ struct status_change *sc_data = battle_get_sc_data(src);
+
+ if(sd) {
+ struct walkpath_data wpd;
+ int dx,dy;
+
+ dx = bl->x - sd->bl.x;
+ dy = bl->y - sd->bl.y;
+ if(dx > 0) dx++;
+ else if(dx < 0) dx--;
+ if(dy > 0) dy++;
+ else if(dy < 0) dy--;
+ if(dx == 0 && dy == 0) dx++;
+ if(path_search(&wpd,src->m,sd->bl.x,sd->bl.y,sd->bl.x+dx,sd->bl.y+dy,1) == -1) {
+ dx = bl->x - sd->bl.x;
+ dy = bl->y - sd->bl.y;
+ if(path_search(&wpd,src->m,sd->bl.x,sd->bl.y,sd->bl.x+dx,sd->bl.y+dy,1) == -1) {
+ clif_skill_fail(sd,sd->skillid,0,0);
+ break;
+ }
+ }
+ sd->to_x = sd->bl.x + dx;
+ sd->to_y = sd->bl.y + dy;
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ clif_walkok(sd);
+ clif_movechar(sd);
+ if(dx < 0) dx = -dx;
+ if(dy < 0) dy = -dy;
+ sd->attackabletime = sd->canmove_tick = tick + 100 + sd->speed * ((dx > dy)? dx:dy);
+ if(sd->canact_tick < sd->canmove_tick)
+ sd->canact_tick = sd->canmove_tick;
+ pc_movepos(sd,sd->to_x,sd->to_y);
+ skill_status_change_end(&sd->bl,SC_COMBO,-1);
+ }
+ else
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ skill_status_change_end(src, SC_EXPLOSIONSPIRITS, -1);
+ if(sc_data && sc_data[SC_BLADESTOP].timer != -1)
+ skill_status_change_end(src,SC_BLADESTOP,-1);
+ }
+ break;
+ /* 武器系範囲攻撃スキル */
+ case AC_SHOWER: /* アローシャワー */
+ case SM_MAGNUM: /* マグナムブレイク */
+ case AS_GRIMTOOTH: /* グリムトゥース */
+ case MC_CARTREVOLUTION: /* カートレヴォリューション */
+ case NPC_SPLASHATTACK: /* スプラッシュアタック */
+ case ASC_METEORASSAULT: /* メテオアサルト */
+ case AS_SPLASHER: /* [Valaris] */
+ if(flag&1){
+ /* 個別にダメージを与える */
+ if(bl->id!=skill_area_temp[1]){
+ int dist=0;
+ if(skillid==SM_MAGNUM){ /* マグナムブレイクなら中心からの距離を計算 */
+ int dx=abs( bl->x - skill_area_temp[2] );
+ int dy=abs( bl->y - skill_area_temp[3] );
+ dist=((dx>dy)?dx:dy);
+ }
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,
+ 0x0500|dist );
+ }
+ }else{
+ int ar=1;
+ int x=bl->x,y=bl->y;
+ if( skillid==SM_MAGNUM){
+ x=src->x;
+ y=src->y;
+ }else if(skillid==AC_SHOWER || skillid==ASC_METEORASSAULT) /* アローシャワー、メテオアサルト範囲5*5 */
+ ar=2;
+ else if(skillid==AS_SPLASHER) /* ベナムスプラッシャー範囲3*3 */
+ ar=1;
+ else if(skillid==NPC_SPLASHATTACK) /* スプラッシュアタックは範囲7*7 */
+ ar=3;
+ skill_area_temp[1]=bl->id;
+ skill_area_temp[2]=x;
+ skill_area_temp[3]=y;
+ /* まずターゲットに攻撃を加える */
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0);
+ /* その後ターゲット以外の範囲内の敵全体に処理を行う */
+ map_foreachinarea(skill_area_sub,
+ bl->m,x-ar,y-ar,x+ar,y+ar,0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
+ skill_castend_damage_id);
+ }
+ break;
+
+ case KN_BOWLINGBASH: /* ボウリングバッシュ */
+ if(flag&1){
+ /* 個別にダメージを与える */
+ if(bl->id!=skill_area_temp[1])
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0x0500);
+ }
+ else {
+ int damage;
+ map_freeblock_lock();
+ damage = skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0);
+ if(damage > 0) {
+ int i,c; /* 他人から聞いた動きなので間違ってる可能性大&効率が悪いっす>< */
+ c = skill_get_blewcount(skillid,skilllv);
+ if(map[bl->m].flag.gvg) c = 0;
+ for(i=0;i<c;i++){
+ skill_blown(src,bl,1);
+ if(bl->type == BL_MOB)
+ clif_fixmobpos((struct mob_data *)bl);
+ else if(bl->type == BL_PET)
+ clif_fixpetpos((struct pet_data *)bl);
+ else
+ clif_fixpos(bl);
+ skill_area_temp[0]=0;
+ map_foreachinarea(skill_area_sub,
+ bl->m,bl->x-1,bl->y-1,bl->x+1,bl->y+1,0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY ,
+ skill_area_sub_count);
+ if(skill_area_temp[0]>1) break;
+ }
+ skill_area_temp[1]=bl->id;
+ skill_area_temp[2]=bl->x;
+ skill_area_temp[3]=bl->y;
+ /* その後ターゲット以外の範囲内の敵全体に処理を行う */
+ map_foreachinarea(skill_area_sub,
+ bl->m,bl->x-1,bl->y-1,bl->x+1,bl->y+1,0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
+ skill_castend_damage_id);
+ battle_damage(src,bl,damage,1);
+ if(rdamage > 0)
+ battle_damage(bl,src,rdamage,0);
+ }
+ map_freeblock_unlock();
+ }
+ break;
+
+ case ALL_RESURRECTION: /* リザレクション */
+ case PR_TURNUNDEAD: /* ターンアンデッド */
+ if(bl->type != BL_PC && battle_check_undead(battle_get_race(bl),battle_get_elem_type(bl)))
+ skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
+ else {
+ map_freeblock_unlock();
+ return 1;
+ }
+ break;
+
+ /* 魔法系スキル */
+ case MG_SOULSTRIKE: /* ソウルストライク */
+ case MG_COLDBOLT: /* コールドボルト */
+ case MG_FIREBOLT: /* ファイアーボルト */
+ case MG_LIGHTNINGBOLT: /* ライトニングボルト */
+ case WZ_EARTHSPIKE: /* アーススパイク */
+ case AL_HEAL: /* ヒール */
+ case AL_HOLYLIGHT: /* ホーリーライト */
+ case MG_FROSTDIVER: /* フロストダイバー */
+ case WZ_JUPITEL: /* ユピテルサンダー */
+ case NPC_MAGICALATTACK: /* MOB:魔法打撃攻撃 */
+ case PR_ASPERSIO: /* アスペルシオ */
+ skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
+ break;
+
+ case WZ_WATERBALL: /* ウォーターボール */
+ skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
+ if(skilllv>1)
+ skill_status_change_start(src,SC_WATERBALL,skilllv,bl->id,0,0,0,0);
+ break;
+
+ case PR_BENEDICTIO: /* 聖体降福 */
+ if(battle_get_race(bl)==1 || battle_get_race(bl)==6)
+ skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
+ break;
+
+ /* 魔法系範囲攻撃スキル */
+ case MG_NAPALMBEAT: /* ナパームビート */
+ case MG_FIREBALL: /* ファイヤーボール */
+ if(flag&1){
+ /* 個別にダメージを与える */
+ if(bl->id!=skill_area_temp[1]){
+ if(skillid==MG_FIREBALL){ /* ファイヤーボールなら中心からの距離を計算 */
+ int dx=abs( bl->x - skill_area_temp[2] );
+ int dy=abs( bl->y - skill_area_temp[3] );
+ skill_area_temp[0]=((dx>dy)?dx:dy);
+ }
+ skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,
+ skill_area_temp[0]| 0x0500);
+ }
+ }else{
+ int ar=(skillid==MG_NAPALMBEAT)?1:2;
+ skill_area_temp[1]=bl->id;
+ if(skillid==MG_NAPALMBEAT){ /* ナパームでは先に数える */
+ skill_area_temp[0]=0;
+ map_foreachinarea(skill_area_sub,
+ bl->m,bl->x-1,bl->y-1,bl->x+1,bl->y+1,0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY ,
+ skill_area_sub_count);
+ }else{
+ skill_area_temp[0]=0;
+ skill_area_temp[2]=bl->x;
+ skill_area_temp[3]=bl->y;
+ }
+ /* まずターゲットに攻撃を加える */
+ skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,
+ skill_area_temp[0] );
+ /* その後ターゲット以外の範囲内の敵全体に処理を行う */
+ map_foreachinarea(skill_area_sub,
+ bl->m,bl->x-ar,bl->y-ar,bl->x+ar,bl->y+ar,0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
+ skill_castend_damage_id);
+ }
+ break;
+
+ case HW_NAPALMVULCAN: // Fixed By SteelViruZ
+ if(flag&1){
+ if(bl->id!=skill_area_temp[1]){
+ skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,
+ skill_area_temp[0]);
+ }
+ }else{
+ int ar=(skillid==HW_NAPALMVULCAN)?1:2;
+ skill_area_temp[1]=bl->id;
+ if(skillid==HW_NAPALMVULCAN){
+ skill_area_temp[0]=0;
+ map_foreachinarea(skill_area_sub,
+ bl->m,bl->x-1,bl->y-1,bl->x+1,bl->y+1,0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY ,
+ skill_area_sub_count);
+ }else{
+ skill_area_temp[0]=0;
+ skill_area_temp[2]=bl->x;
+ skill_area_temp[3]=bl->y;
+ }
+ skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,
+ skill_area_temp[0] );
+ map_foreachinarea(skill_area_sub,
+ bl->m,bl->x-ar,bl->y-ar,bl->x+ar,bl->y+ar,0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
+ skill_castend_damage_id);
+ }
+ break;
+
+ case WZ_FROSTNOVA: /* フロストノヴァ */
+ skill_castend_pos2(src,bl->x,bl->y,skillid,skilllv,tick,0);
+ skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
+ break;
+
+ case WZ_SIGHTRASHER:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_castend_pos2(src,bl->x,bl->y,skillid,skilllv,tick,0);
+ skill_status_change_end(src,SC_SIGHT,-1);
+ break;
+
+ /* その他 */
+ case HT_BLITZBEAT: /* ブリッツビート */
+ if(flag&1){
+ /* 個別にダメージを与える */
+ if(bl->id!=skill_area_temp[1])
+ skill_attack(BF_MISC,src,src,bl,skillid,skilllv,tick,skill_area_temp[0]|(flag&0xf00000));
+ }else{
+ skill_area_temp[0]=0;
+ skill_area_temp[1]=bl->id;
+ if(flag&0xf00000)
+ map_foreachinarea(skill_area_sub,bl->m,bl->x-1,bl->y-1,bl->x+1,bl->y+1,0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY ,skill_area_sub_count);
+ /* まずターゲットに攻撃を加える */
+ skill_attack(BF_MISC,src,src,bl,skillid,skilllv,tick,skill_area_temp[0]|(flag&0xf00000));
+ /* その後ターゲット以外の範囲内の敵全体に処理を行う */
+ map_foreachinarea(skill_area_sub,
+ bl->m,bl->x-1,bl->y-1,bl->x+1,bl->y+1,0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
+ skill_castend_damage_id);
+ }
+ break;
+
+ case CR_GRANDCROSS: /* グランドクロス */
+ /* スキルユニット配置 */
+ skill_castend_pos2(src,bl->x,bl->y,skillid,skilllv,tick,0);
+ if(sd)
+ sd->canmove_tick = tick + 1000;
+ else if(src->type == BL_MOB)
+ mob_changestate((struct mob_data *)src,MS_DELAY,1000);
+ break;
+
+ case TF_THROWSTONE: /* 石投げ */
+ case NPC_SMOKING: /* スモーキング */
+ skill_attack(BF_MISC,src,src,bl,skillid,skilllv,tick,0 );
+ break;
+
+ case NPC_SELFDESTRUCTION: /* 自爆 */
+ case NPC_SELFDESTRUCTION2: /* 自爆2 */
+ if(flag&1){
+ /* 個別にダメージを与える */
+ if(src->type==BL_MOB){
+ struct mob_data* mb = (struct mob_data*)src;
+ nullpo_retr(1, mb);
+ mb->hp=skill_area_temp[2];
+ if(bl->id!=skill_area_temp[1])
+ skill_attack(BF_MISC,src,src,bl,NPC_SELFDESTRUCTION,skilllv,tick,flag );
+ mb->hp=1;
+ }
+ }else{
+ struct mob_data *md;
+ if((md=(struct mob_data *)src)){
+ skill_area_temp[1]=bl->id;
+ skill_area_temp[2]=battle_get_hp(src);
+ clif_skill_nodamage(src,src,NPC_SELFDESTRUCTION,-1,1);
+ map_foreachinarea(skill_area_sub,
+ bl->m,bl->x-5,bl->y-5,bl->x+5,bl->y+5,0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
+ skill_castend_damage_id);
+ battle_damage(src,src,md->hp,0);
+ }
+ }
+ break;
+
+ /* HP吸収/HP吸収魔法 */
+ case NPC_BLOODDRAIN:
+ case NPC_ENERGYDRAIN:
+ {
+ int heal;
+ heal = skill_attack((skillid==NPC_BLOODDRAIN)?BF_WEAPON:BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
+ if( heal > 0 ){
+ struct block_list tbl;
+ tbl.id = 0;
+ tbl.m = src->m;
+ tbl.x = src->x;
+ tbl.y = src->y;
+ clif_skill_nodamage(&tbl,src,AL_HEAL,heal,1);
+ battle_heal(NULL,src,heal,0,0);
+ }
+ }
+ break;
+ case 0:
+ if(sd) {
+ if(flag&3){
+ if(bl->id!=skill_area_temp[1])
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0x0500);
+ }
+ else{
+ int ar=sd->splash_range;
+ skill_area_temp[1]=bl->id;
+ map_foreachinarea(skill_area_sub,
+ bl->m, bl->x - ar, bl->y - ar, bl->x + ar, bl->y + ar, 0,
+ src, skillid, skilllv, tick, flag | BCT_ENEMY | 1,
+ skill_castend_damage_id);
+ }
+ }
+ break;
+
+ default:
+ map_freeblock_unlock();
+ return 1;
+ }
+ map_freeblock_unlock();
+
+ return 0;
+}
+
+/*==========================================
+ * スキル使用(詠唱完了、ID指定支援系)
+ *------------------------------------------
+ */
+int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag )
+{
+ struct map_session_data *sd=NULL;
+ struct map_session_data *dstsd=NULL;
+ struct mob_data *md=NULL;
+ struct mob_data *dstmd=NULL;
+ int i,abra_skillid=0,abra_skilllv;
+ int sc_def_vit,sc_def_mdef,strip_fix,strip_time,strip_per;
+ int sc_dex,sc_luk;
+ //クラスチェンジ用ボスモンスターID
+ int changeclass[]={1038,1039,1046,1059,1086,1087,1112,1115
+ ,1157,1159,1190,1272,1312,1373,1492};
+ int poringclass[]={1002};
+
+ nullpo_retr(1, src);
+ nullpo_retr(1, bl);
+
+ if(src->type==BL_PC)
+ sd=(struct map_session_data *)src;
+ else if(src->type==BL_MOB)
+ md=(struct mob_data *)src;
+
+ sc_dex=battle_get_mdef(bl);
+ sc_luk=battle_get_luk(bl);
+ sc_def_vit = 100 - (3 + battle_get_vit(bl) + battle_get_luk(bl)/3);
+ //sc_def_vit = 100 - (3 + battle_get_vit(bl) + battle_get_luk(bl)/3);
+ sc_def_mdef = 100 - (3 + battle_get_mdef(bl) + battle_get_luk(bl)/3);
+ strip_fix = battle_get_dex(src) - battle_get_dex(bl);
+
+ if(bl->type==BL_PC){
+ nullpo_retr(1, dstsd=(struct map_session_data *)bl);
+ }else if(bl->type==BL_MOB){
+ nullpo_retr(1, dstmd=(struct mob_data *)bl);
+ if(sc_def_vit>50)
+ sc_def_vit=50;
+ if(sc_def_mdef>50)
+ sc_def_mdef=50;
+ }
+ if(sc_def_vit < 0)
+ sc_def_vit=0;
+ if(sc_def_mdef < 0)
+ sc_def_mdef=0;
+ if(strip_fix < 0)
+ strip_fix=0;
+
+ if(bl == NULL || bl->prev == NULL)
+ return 1;
+ if(sd && pc_isdead(sd))
+ return 1;
+ if(dstsd && pc_isdead(dstsd) && skillid != ALL_RESURRECTION)
+ return 1;
+ if(battle_get_class(bl) == 1288)
+ return 1;
+ if (skillnotok(skillid, (struct map_session_data *)bl)) // [MouseJstr]
+ return 0;
+
+ map_freeblock_lock();
+ switch(skillid)
+ {
+ case AL_HEAL: /* ヒール */
+ {
+ int heal=skill_calc_heal( src, skilllv );
+ int heal_get_jobexp;
+ int skill;
+ struct pc_base_job s_class;
+
+ if( dstsd && dstsd->special_state.no_magic_damage )
+ heal=0; /* 黄金蟲カード(ヒール量0) */
+ if (sd){
+ s_class = pc_calc_base_job(sd->status.class);
+ if((skill=pc_checkskill(sd,HP_MEDITATIO))>0) // メディテイティオ
+ heal += heal*(skill*2/100);
+ if(sd && dstsd && sd->status.partner_id == dstsd->status.char_id && s_class.job == 23 && sd->status.sex == 0) //自分も対象もPC、対象が自分のパートナー、自分がスパノビ、自分が♀なら
+ heal = heal*2; //スパノビの嫁が旦那にヒールすると2倍になる
+ }
+
+
+ clif_skill_nodamage(src,bl,skillid,heal,1);
+ heal_get_jobexp = battle_heal(NULL,bl,heal,0,0);
+
+ // JOB経験値獲得
+ if(src->type == BL_PC && bl->type==BL_PC && heal > 0 && src != bl && battle_config.heal_exp > 0){
+ heal_get_jobexp = heal_get_jobexp * battle_config.heal_exp / 100;
+ if(heal_get_jobexp <= 0)
+ heal_get_jobexp = 1;
+ pc_gainexp((struct map_session_data *)src,0,heal_get_jobexp);
+ }
+ }
+ break;
+
+ case ALL_RESURRECTION: /* リザレクション */
+ if(bl->type==BL_PC){
+ int per=0;
+ struct map_session_data *tsd = (struct map_session_data*)bl;
+ nullpo_retr(1, tsd);
+ if( (map[bl->m].flag.pvp) && tsd->pvp_point<0 )
+ break; /* PVPで復活不可能状態 */
+
+ if(pc_isdead(tsd)){ /* 死亡判定 */
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ switch(skilllv){
+ case 1: per=10; break;
+ case 2: per=30; break;
+ case 3: per=50; break;
+ case 4: per=80; break;
+ }
+ tsd->status.hp=tsd->status.max_hp*per/100;
+ if(tsd->status.hp<=0) tsd->status.hp=1;
+ if(tsd->special_state.restart_full_recover ){ /* オシリスカード */
+ tsd->status.hp=tsd->status.max_hp;
+ tsd->status.sp=tsd->status.max_sp;
+ }
+ pc_setstand(tsd);
+ if(battle_config.pc_invincible_time > 0)
+ pc_setinvincibletimer(tsd,battle_config.pc_invincible_time);
+ clif_updatestatus(tsd,SP_HP);
+ clif_resurrection(&tsd->bl,1);
+ if(src != bl && sd && battle_config.resurrection_exp > 0) {
+ int exp = 0,jexp = 0;
+ int lv = tsd->status.base_level - sd->status.base_level, jlv = tsd->status.job_level - sd->status.job_level;
+ if(lv > 0) {
+ exp = (int)((double)tsd->status.base_exp * (double)lv * (double)battle_config.resurrection_exp / 1000000.);
+ if(exp < 1) exp = 1;
+ }
+ if(jlv > 0) {
+ jexp = (int)((double)tsd->status.job_exp * (double)lv * (double)battle_config.resurrection_exp / 1000000.);
+ if(jexp < 1) jexp = 1;
+ }
+ if(exp > 0 || jexp > 0)
+ pc_gainexp(sd,exp,jexp);
+ }
+ }
+ }
+ break;
+
+ case AL_DECAGI: /* 速度減少 */
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
+ break;
+ if( rand()%100 < (50+skilllv*3+(battle_get_lv(src)+battle_get_int(src)/5)-sc_def_mdef) ) {
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0);
+ }
+ break;
+
+ case AL_CRUCIS:
+ if(flag&1) {
+ int race = battle_get_race(bl),ele = battle_get_elem_type(bl);
+ if(battle_check_target(src,bl,BCT_ENEMY) && (race == 6 || battle_check_undead(race,ele))) {
+ int slv=battle_get_lv(src),tlv=battle_get_lv(bl),rate;
+ rate = 25 + skilllv*2 + slv - tlv;
+ if(rand()%100 < rate)
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,0,0);
+ }
+ }
+ else {
+ int range = 15;
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ map_foreachinarea(skill_area_sub,
+ src->m,src->x-range,src->y-range,src->x+range,src->y+range,0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
+ skill_castend_nodamage_id);
+ }
+ break;
+
+ case PR_LEXDIVINA: /* レックスディビーナ */
+ {
+ struct status_change *sc_data = battle_get_sc_data(bl);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
+ break;
+ if(sc_data && sc_data[SC_DIVINA].timer != -1)
+ skill_status_change_end(bl,SC_DIVINA,-1);
+ else if( rand()%100 < sc_def_vit ) {
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0);
+ }
+ }
+ break;
+ case SA_ABRACADABRA:
+ //require 1 yellow gemstone even with mistress card or Into the Abyss
+ if (pc_search_inventory(sd, 715) <= 0 ) {
+ clif_skill_fail(sd,sd->skillid,0,0);
+ break;
+ }
+ pc_delitem(sd, pc_search_inventory(sd, 715), 1, 0);
+ //
+ do{
+ abra_skillid=skill_abra_dataset(skilllv);
+ }while(abra_skillid == 0);
+ abra_skilllv=skill_get_max(abra_skillid)>pc_checkskill(sd,SA_ABRACADABRA)?pc_checkskill(sd,SA_ABRACADABRA):skill_get_max(abra_skillid);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ sd->skillitem=abra_skillid;
+ sd->skillitemlv=abra_skilllv;
+ clif_item_skill(sd,abra_skillid,abra_skilllv,"アブラカダブラ");
+ break;
+ case SA_COMA:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
+ break;
+ if(dstsd){
+ dstsd->status.hp=1;
+ dstsd->status.sp=1;
+ clif_updatestatus(dstsd,SP_HP);
+ clif_updatestatus(dstsd,SP_SP);
+ }
+ if(dstmd) dstmd->hp=1;
+ break;
+ case SA_FULLRECOVERY:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
+ break;
+ if(dstsd) pc_heal(dstsd,dstsd->status.max_hp,dstsd->status.max_sp);
+ if(dstmd) dstmd->hp=battle_get_max_hp(&dstmd->bl);
+ break;
+ case SA_SUMMONMONSTER:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if (sd) mob_once_spawn(sd,map[sd->bl.m].name,sd->bl.x,sd->bl.y,"--ja--",-1,1,"");
+ break;
+ case SA_LEVELUP:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if (sd && pc_nextbaseexp(sd)) pc_gainexp(sd,pc_nextbaseexp(sd)*10/100,0);
+ break;
+
+ case SA_INSTANTDEATH:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if (sd) pc_damage(NULL,sd,sd->status.max_hp);
+ break;
+
+ case SA_QUESTION:
+ case SA_GRAVITY:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ break;
+ case SA_CLASSCHANGE:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if(dstmd) mob_class_change(dstmd,changeclass);
+ break;
+ case SA_MONOCELL:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if(dstmd) mob_class_change(dstmd,poringclass);
+ break;
+ case SA_DEATH:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if (dstsd) pc_damage(NULL,dstsd,dstsd->status.max_hp);
+ if (dstmd) mob_damage(NULL,dstmd,dstmd->hp,1);
+ break;
+ case SA_REVERSEORCISH:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if (dstsd) pc_setoption(dstsd,dstsd->status.option|0x0800);
+ break;
+ case SA_FORTUNE:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if(sd) pc_getzeny(sd,battle_get_lv(bl)*100);
+ break;
+ case SA_TAMINGMONSTER:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if (dstmd){
+ for(i=0;i<MAX_PET_DB;i++){
+ if(dstmd->class == pet_db[i].class){
+ pet_catch_process1(sd,dstmd->class);
+ break;
+ }
+ }
+ }
+ break;
+ case AL_INCAGI: /* 速度増加 */
+ case AL_BLESSING: /* ブレッシング */
+ case PR_SLOWPOISON:
+ case PR_IMPOSITIO: /* イムポシティオマヌス */
+ case PR_LEXAETERNA: /* レックスエーテルナ */
+ case PR_SUFFRAGIUM: /* サフラギウム */
+ case PR_BENEDICTIO: /* 聖体降福 */
+ case CR_PROVIDENCE: /* プロヴィデンス */
+ case CG_MARIONETTE: /* マリオネットコントロール */
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage ){
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ }else{
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ }
+ break;
+
+ case SA_FLAMELAUNCHER: // added failure chance and chance to break weapon if turned on [Valaris]
+ case SA_FROSTWEAPON:
+ case SA_LIGHTNINGLOADER:
+ case SA_SEISMICWEAPON:
+ if(bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage ){
+ clif_skill_nodamage(src,bl,skillid,skilllv,0);
+ break;
+ }
+ if(bl->type==BL_PC) {
+ struct map_session_data *sd2=(struct map_session_data *)bl;
+ if(sd2->status.weapon==0 || sd2->sc_data[SC_FLAMELAUNCHER].timer!=-1 || sd2->sc_data[SC_FROSTWEAPON].timer!=-1 ||
+ sd2->sc_data[SC_LIGHTNINGLOADER].timer!=-1 || sd2->sc_data[SC_SEISMICWEAPON].timer!=-1 ||
+ sd2->sc_data[SC_ENCPOISON].timer!=-1) {
+ clif_skill_fail(sd,skillid,0,0);
+ clif_skill_nodamage(src,bl,skillid,skilllv,0);
+ break;
+ }
+ }
+ if(rand()%100 > (75+skilllv*1) && (skilllv != 5)) {
+ clif_skill_fail(sd,skillid,0,0);
+ clif_skill_nodamage(src,bl,skillid,skilllv,0);
+ if(bl->type==BL_PC && battle_config.equipment_breaking) {
+ struct map_session_data *sd2=(struct map_session_data *)bl;
+ if(sd!=sd2) clif_displaymessage(sd->fd,"You broke target's weapon");
+ pc_breakweapon(sd2);
+ }
+ break;
+ }
+ else {
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ }
+ break;
+
+ case PR_ASPERSIO: /* アスペルシオ */
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
+ break;
+ if(bl->type==BL_MOB)
+ break;
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+ break;
+ case PR_KYRIE: /* キリエエレイソン */
+ clif_skill_nodamage(bl,bl,skillid,skilllv,1);
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
+ break;
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+ break;
+ case KN_AUTOCOUNTER: /* オートカウンター */
+ case KN_TWOHANDQUICKEN: /* ツーハンドクイッケン */
+ case CR_SPEARQUICKEN: /* スピアクイッケン */
+ case CR_REFLECTSHIELD:
+ case AS_POISONREACT: /* ポイズンリアクト */
+ case MC_LOUD: /* ラウドボイス */
+ case MG_ENERGYCOAT: /* エナジーコート */
+ case SM_ENDURE: /* インデュア */
+ case MG_SIGHT: /* サイト */
+ case AL_RUWACH: /* ルアフ */
+ case MO_EXPLOSIONSPIRITS: // 爆裂波動
+ case MO_STEELBODY: // 金剛
+ case LK_AURABLADE: /* オーラブレード */
+ case LK_PARRYING: /* パリイング */
+ case LK_CONCENTRATION: /* コンセントレーション */
+ case LK_BERSERK: /* バーサーク */
+ case HP_ASSUMPTIO: /* */
+ case WS_CARTBOOST: /* カートブースト */
+ case SN_SIGHT: /* トゥルーサイト */
+ case WS_MELTDOWN: /* メルトダウン */
+ case ST_REJECTSWORD: /* リジェクトソード */
+ case HW_MAGICPOWER: /* 魔法力増幅 */
+ case PF_MEMORIZE: /* メモライズ */
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+ break;
+ case AS_ENCHANTPOISON: // Prevent spamming [Valaris]
+ if(bl->type==BL_PC) {
+ struct map_session_data *sd2=(struct map_session_data *)bl;
+ if(sd2->sc_data[SC_FLAMELAUNCHER].timer!=-1 || sd2->sc_data[SC_FROSTWEAPON].timer!=-1 ||
+ sd2->sc_data[SC_LIGHTNINGLOADER].timer!=-1 || sd2->sc_data[SC_SEISMICWEAPON].timer!=-1 ||
+ sd2->sc_data[SC_ENCPOISON].timer!=-1) {
+ clif_skill_nodamage(src,bl,skillid,skilllv,0);
+ clif_skill_fail(sd,skillid,0,0);
+ break;
+ }
+ }
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+ break;
+ case LK_TENSIONRELAX: /* テンションリラックス */
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ pc_setsit(sd);
+ clif_sitting(sd->fd,sd);
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+ break;
+ case MC_CHANGECART:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ break;
+ case AC_CONCENTRATION: /* 集中力向上 */
+ {
+ int range = 1;
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+ map_foreachinarea( skill_status_change_timer_sub,
+ src->m, src->x-range, src->y-range, src->x+range,src->y+range,0,
+ src,SkillStatusChangeTable[skillid],tick);
+ }
+ break;
+ case SM_PROVOKE: /* プロボック */
+ {
+ struct status_change *sc_data = battle_get_sc_data(bl);
+
+ /* MVPmobと不死には効かない */
+ if((bl->type==BL_MOB && battle_get_mode(bl)&0x20) || battle_check_undead(battle_get_race(bl),battle_get_elem_type(bl))) //不死には効かない
+ {
+ map_freeblock_unlock();
+ return 1;
+ }
+
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+
+ if(dstmd && dstmd->skilltimer!=-1 && dstmd->state.skillcastcancel) // 詠唱妨害
+ skill_castcancel(bl,0);
+ if(dstsd && dstsd->skilltimer!=-1 && (!dstsd->special_state.no_castcancel || map[bl->m].flag.gvg)
+ && dstsd->state.skillcastcancel && !dstsd->special_state.no_castcancel2)
+ skill_castcancel(bl,0);
+
+ if(sc_data){
+ if(sc_data[SC_FREEZE].timer!=-1)
+ skill_status_change_end(bl,SC_FREEZE,-1);
+ if(sc_data[SC_STONE].timer!=-1 && sc_data[SC_STONE].val2==0)
+ skill_status_change_end(bl,SC_STONE,-1);
+ if(sc_data[SC_SLEEP].timer!=-1)
+ skill_status_change_end(bl,SC_SLEEP,-1);
+ }
+
+ if(bl->type==BL_MOB) {
+ int range = skill_get_range(skillid,skilllv);
+ if(range < 0)
+ range = battle_get_range(src) - (range + 1);
+ mob_target((struct mob_data *)bl,src,range);
+ }
+ }
+ break;
+
+ case CR_DEVOTION: /* ディボーション */
+ if(sd && dstsd){
+ //転生や養子の場合の元の職業を算出する
+
+ int lv = sd->status.base_level-dstsd->status.base_level;
+ lv = (lv<0)?-lv:lv;
+ if((dstsd->bl.type!=BL_PC) // 相手はPCじゃないとだめ
+ ||(sd->bl.id == dstsd->bl.id) // 相手が自分はだめ
+ ||(lv > 10) // レベル差±10まで
+ ||(!sd->status.party_id && !sd->status.guild_id) // PTにもギルドにも所属無しはだめ
+ ||((sd->status.party_id != dstsd->status.party_id) // 同じパーティーか、
+ ||(sd->status.guild_id != dstsd->status.guild_id)) // 同じギルドじゃないとだめ
+ ||(dstsd->status.class==14||dstsd->status.class==21
+ ||dstsd->status.class==4015||dstsd->status.class==4022)){ // クルセだめ
+ clif_skill_fail(sd,skillid,0,0);
+ map_freeblock_unlock();
+ return 1;
+ }
+ for(i=0;i<skilllv;i++){
+ if(!sd->dev.val1[i]){ // 空きがあったら入れる
+ sd->dev.val1[i] = bl->id;
+ sd->dev.val2[i] = bl->id;
+ break;
+ }else if(i==skilllv-1){ // 空きがなかった
+ clif_skill_fail(sd,skillid,0,0);
+ map_freeblock_unlock();
+ return 1;
+ }
+ }
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ clif_devotion(sd,bl->id);
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],src->id,1,0,0,1000*(15+15*skilllv),0 );
+ }
+ else clif_skill_fail(sd,skillid,0,0);
+ break;
+ case MO_CALLSPIRITS: // 気功
+ if(sd) {
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ pc_addspiritball(sd,skill_get_time(skillid,skilllv),skilllv);
+ }
+ break;
+ case CH_SOULCOLLECT: // 狂気功
+ if(sd) {
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ for(i=0;i<5;i++)
+ pc_addspiritball(sd,skill_get_time(skillid,skilllv),5);
+ }
+ break;
+ case MO_BLADESTOP: // 白刃取り
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_status_change_start(src,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+ break;
+ case MO_ABSORBSPIRITS: // 気奪
+ i=0;
+ if(sd && dstsd) {
+ if(sd == dstsd || map[sd->bl.m].flag.pvp || map[sd->bl.m].flag.gvg) {
+ if(dstsd->spiritball > 0) {
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ i = dstsd->spiritball * 7;
+ pc_delspiritball(dstsd,dstsd->spiritball,0);
+ if(i > 0x7FFF)
+ i = 0x7FFF;
+ if(sd->status.sp + i > sd->status.max_sp)
+ i = sd->status.max_sp - sd->status.sp;
+ }
+ }
+ }else if(sd && dstmd){ //対象がモンスターの場合
+ //20%の確率で対象のLv*2のSPを回復する。成功したときはターゲット(σ゚Д゚)σゲッツ!!
+ if(rand()%100<20){
+ i=2*mob_db[dstmd->class].lv;
+ mob_target(dstmd,src,0);
+ }
+ }
+ if(i){
+ sd->status.sp += i;
+ clif_heal(sd->fd,SP_SP,i);
+ }
+ else
+ clif_skill_nodamage(src,bl,skillid,skilllv,0);
+ break;
+
+ case AC_MAKINGARROW: /* 矢作成 */
+ if(sd) {
+ clif_arrow_create_list(sd);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ }
+ break;
+
+ case AM_PHARMACY: /* ポーション作成 */
+ if(sd) {
+ clif_skill_produce_mix_list(sd,32);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ }
+ break;
+ case WS_CREATECOIN: /* クリエイトコイン */
+ if(sd) {
+ clif_skill_produce_mix_list(sd,64);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ }
+ break;
+ case WS_CREATENUGGET: /* 塊製造 */
+ if(sd) {
+ clif_skill_produce_mix_list(sd,128);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ }
+ break;
+ case BS_HAMMERFALL: /* ハンマーフォール */
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_weapon_damage )
+ break;
+ if( rand()%100 < (20+ 10*skilllv)*sc_def_vit/100 ) {
+ skill_status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ }
+ break;
+
+ case RG_RAID: /* サプライズアタック */
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ {
+ int x=bl->x,y=bl->y;
+ skill_area_temp[1]=bl->id;
+ skill_area_temp[2]=x;
+ skill_area_temp[3]=y;
+ map_foreachinarea(skill_area_sub,
+ bl->m,x-1,y-1,x+1,y+1,0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
+ skill_castend_damage_id);
+ }
+ skill_status_change_end(src, SC_HIDING, -1); // ハイディング解除
+ break;
+
+ case KN_BRANDISHSPEAR: /*ブランディッシュスピア*/
+ {
+ int c,n=4,ar;
+ int dir = map_calc_dir(src,bl->x,bl->y);
+ struct square tc;
+ int x=bl->x,y=bl->y;
+ ar=skilllv/3;
+ skill_brandishspear_first(&tc,dir,x,y);
+ skill_brandishspear_dir(&tc,dir,4);
+ /* 範囲C */
+ if(skilllv == 10){
+ for(c=1;c<4;c++){
+ map_foreachinarea(skill_area_sub,
+ bl->m,tc.val1[c],tc.val2[c],tc.val1[c],tc.val2[c],0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY|n,
+ skill_castend_damage_id);
+ }
+ }
+ /* 範囲BA */
+ if(skilllv > 6){
+ skill_brandishspear_dir(&tc,dir,-1);
+ n--;
+ }else{
+ skill_brandishspear_dir(&tc,dir,-2);
+ n-=2;
+ }
+
+ if(skilllv > 3){
+ for(c=0;c<5;c++){
+ map_foreachinarea(skill_area_sub,
+ bl->m,tc.val1[c],tc.val2[c],tc.val1[c],tc.val2[c],0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY|n,
+ skill_castend_damage_id);
+ if(skilllv > 6 && n==3 && c==4){
+ skill_brandishspear_dir(&tc,dir,-1);
+ n--;c=-1;
+ }
+ }
+ }
+ /* 範囲@ */
+ for(c=0;c<10;c++){
+ if(c==0||c==5) skill_brandishspear_dir(&tc,dir,-1);
+ map_foreachinarea(skill_area_sub,
+ bl->m,tc.val1[c%5],tc.val2[c%5],tc.val1[c%5],tc.val2[c%5],0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
+ skill_castend_damage_id);
+ }
+ }
+ break;
+
+ /* パーティスキル */
+ case AL_ANGELUS: /* エンジェラス */
+ case PR_MAGNIFICAT: /* マグニフィカート */
+ case PR_GLORIA: /* グロリア */
+ case SN_WINDWALK: /* ウインドウォーク */
+ if(sd == NULL || sd->status.party_id==0 || (flag&1) ){
+ /* 個別の処理 */
+ clif_skill_nodamage(bl,bl,skillid,skilllv,1);
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
+ break;
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0);
+ }
+ else{
+ /* パーティ全体への処理 */
+ party_foreachsamemap(skill_area_sub,
+ sd,1,
+ src,skillid,skilllv,tick, flag|BCT_PARTY|1,
+ skill_castend_nodamage_id);
+ }
+ break;
+ case BS_ADRENALINE: /* アドレナリンラッシュ */
+ case BS_WEAPONPERFECT: /* ウェポンパーフェクション */
+ case BS_OVERTHRUST: /* オーバートラスト */
+ if(sd == NULL || sd->status.party_id==0 || (flag&1) ){
+ /* 個別の処理 */
+ clif_skill_nodamage(bl,bl,skillid,skilllv,1);
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,(src == bl)? 1:0,0,0,skill_get_time(skillid,skilllv),0);
+ }
+ else{
+ /* パーティ全体への処理 */
+ party_foreachsamemap(skill_area_sub,
+ sd,1,
+ src,skillid,skilllv,tick, flag|BCT_PARTY|1,
+ skill_castend_nodamage_id);
+ }
+ break;
+
+ /*(付加と解除が必要) */
+ case BS_MAXIMIZE: /* マキシマイズパワー */
+ case NV_TRICKDEAD: /* 死んだふり */
+ case CR_DEFENDER: /* ディフェンダー */
+ case CR_AUTOGUARD: /* オートガード */
+ {
+ struct status_change *tsc_data = battle_get_sc_data(bl);
+ int sc=SkillStatusChangeTable[skillid];
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if( tsc_data ){
+ if( tsc_data[sc].timer==-1 )
+ /* 付加する */
+ skill_status_change_start(bl,sc,skilllv,0,0,0,skill_get_time(skillid,skilllv),0);
+ else
+ /* 解除する */
+ skill_status_change_end(bl, sc, -1);
+ }
+ }
+ break;
+
+ case TF_HIDING: /* ハイディング */
+ {
+ struct status_change *tsc_data = battle_get_sc_data(bl);
+ int sc=SkillStatusChangeTable[skillid];
+ clif_skill_nodamage(src,bl,skillid,-1,1);
+ if( tsc_data ){
+ if( tsc_data[sc].timer==-1 )
+ /* 付加する */
+ skill_status_change_start(bl,sc,skilllv,0,0,0,skill_get_time(skillid,skilllv),0);
+ else
+ /* 解除する */
+ skill_status_change_end(bl, sc, -1);
+ }
+ }
+ break;
+
+ case AS_CLOAKING: /* クローキング */
+ {
+ struct status_change *tsc_data = battle_get_sc_data(bl);
+ int sc=SkillStatusChangeTable[skillid];
+ clif_skill_nodamage(src,bl,skillid,-1,1);
+ if( tsc_data ){
+ if( tsc_data[sc].timer==-1 )
+ /* 付加する */
+ skill_status_change_start(bl,sc,skilllv,0,0,0,skill_get_time(skillid,skilllv),0);
+ else
+ /* 解除する */
+ skill_status_change_end(bl, sc, -1);
+ }
+
+ skill_check_cloaking(bl);
+ }
+ break;
+
+ case ST_CHASEWALK: /* ハイディング */
+ {
+ struct status_change *tsc_data = battle_get_sc_data(bl);
+ int sc=SkillStatusChangeTable[skillid];
+ clif_skill_nodamage(src,bl,skillid,-1,1);
+ if( tsc_data ){
+ if( tsc_data[sc].timer==-1 )
+ /* 付加する */
+ skill_status_change_start(bl,sc,skilllv,0,0,0,skill_get_time(skillid,skilllv),0);
+ else
+ /* 解除する */
+ skill_status_change_end(bl, sc, -1);
+ }
+ }
+ break;
+
+ /* 対地スキル */
+ case BD_LULLABY: /* 子守唄 */
+ case BD_RICHMANKIM: /* ニヨルドの宴 */
+ case BD_ETERNALCHAOS: /* 永遠の混沌 */
+ case BD_DRUMBATTLEFIELD: /* 戦太鼓の響き */
+ case BD_RINGNIBELUNGEN: /* ニーベルングの指輪 */
+ case BD_ROKISWEIL: /* ロキの叫び */
+ case BD_INTOABYSS: /* 深淵の中に */
+ case BD_SIEGFRIED: /* 不死身のジークフリード */
+ case BA_DISSONANCE: /* 不協和音 */
+ case BA_POEMBRAGI: /* ブラギの詩 */
+ case BA_WHISTLE: /* 口笛 */
+ case BA_ASSASSINCROSS: /* 夕陽のアサシンクロス */
+ case BA_APPLEIDUN: /* イドゥンの林檎 */
+ case DC_UGLYDANCE: /* 自分勝手なダンス */
+ case DC_HUMMING: /* ハミング */
+ case DC_DONTFORGETME: /* 私を忘れないで… */
+ case DC_FORTUNEKISS: /* 幸運のキス */
+ case DC_SERVICEFORYOU: /* サービスフォーユー */
+ case CG_MOONLIT: /* 月明りの泉に落ちる花びら */
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_unitsetting(src,skillid,skilllv,src->x,src->y,0);
+ break;
+
+ case HP_BASILICA: /* バジリカ */
+ case PA_GOSPEL: /* ゴスペル */
+ skill_clear_unitgroup(src);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_unitsetting(src,skillid,skilllv,src->x,src->y,0);
+ break;
+
+ case BD_ADAPTATION: /* アドリブ */
+ {
+ struct status_change *sc_data = battle_get_sc_data(src);
+ if(sc_data && sc_data[SC_DANCING].timer!=-1){
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_stop_dancing(src,0);
+ }
+ }
+ break;
+
+ case BA_FROSTJOKE: /* 寒いジョーク */
+ case DC_SCREAM: /* スクリーム */
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_addtimerskill(src,tick+3000,bl->id,0,0,skillid,skilllv,0,flag);
+ break;
+
+ case TF_STEAL: // スティール
+ if(sd) {
+ if(pc_steal_item(sd,bl))
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ else
+ clif_skill_nodamage(src,bl,skillid,skilllv,0);
+ }
+ break;
+
+ case RG_STEALCOIN: // スティールコイン
+ if(sd) {
+ if(pc_steal_coin(sd,bl)) {
+ int range = skill_get_range(skillid,skilllv);
+ if(range < 0)
+ range = battle_get_range(src) - (range + 1);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ mob_target((struct mob_data *)bl,src,range);
+ }
+ else
+ clif_skill_nodamage(src,bl,skillid,skilllv,0);
+ }
+ break;
+
+ case MG_STONECURSE: /* ストーンカース */
+ if (bl->type==BL_MOB && battle_get_mode(bl)&0x20) {
+ clif_skill_fail(sd,sd->skillid,0,0);
+ break;
+ }
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
+ break;
+ if( rand()%100 < skilllv*4+20 && !battle_check_undead(battle_get_race(bl),battle_get_elem_type(bl)))
+ skill_status_change_start(bl,SC_STONE,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ else if(sd)
+ clif_skill_fail(sd,skillid,0,0);
+ break;
+
+ case NV_FIRSTAID: /* 応急手当 */
+ clif_skill_nodamage(src,bl,skillid,5,1);
+ battle_heal(NULL,bl,5,0,0);
+ break;
+
+ case AL_CURE: /* キュアー */
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
+ break;
+ skill_status_change_end(bl, SC_SILENCE , -1 );
+ skill_status_change_end(bl, SC_BLIND , -1 );
+ skill_status_change_end(bl, SC_CONFUSION, -1 );
+ if( battle_check_undead(battle_get_race(bl),battle_get_elem_type(bl)) ){//アンデッドなら暗闇効果
+ skill_status_change_start(bl, SC_CONFUSION,1,0,0,0,6000,0);
+ }
+ break;
+
+ case TF_DETOXIFY: /* 解毒 */
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_status_change_end(bl, SC_POISON , -1 );
+ break;
+
+ case PR_STRECOVERY: /* リカバリー */
+ {
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
+ break;
+ skill_status_change_end(bl, SC_FREEZE , -1 );
+ skill_status_change_end(bl, SC_STONE , -1 );
+ skill_status_change_end(bl, SC_SLEEP , -1 );
+ skill_status_change_end(bl, SC_STAN , -1 );
+ if( battle_check_undead(battle_get_race(bl),battle_get_elem_type(bl)) ){//アンデッドなら暗闇効果
+ int blind_time;
+ //blind_time=30-battle_get_vit(bl)/10-battle_get_int/15;
+ blind_time=30*(100-(battle_get_int(bl)+battle_get_vit(bl))/2)/100;
+ if(rand()%100 < (100-(battle_get_int(bl)/2+battle_get_vit(bl)/3+battle_get_luk(bl)/10)))
+ skill_status_change_start(bl, SC_BLIND,1,0,0,0,blind_time,0);
+ }
+ if(dstmd){
+ dstmd->attacked_id=0;
+ dstmd->target_id=0;
+ dstmd->state.targettype = NONE_ATTACKABLE;
+ dstmd->state.skillstate=MSS_IDLE;
+ dstmd->next_walktime=tick+rand()%3000+3000;
+ }
+ }
+ break;
+
+ case WZ_ESTIMATION: /* モンスター情報 */
+ if(src->type==BL_PC){
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ clif_skill_estimation((struct map_session_data *)src,bl);
+ }
+ break;
+
+ case MC_IDENTIFY: /* アイテム鑑定 */
+ if(sd)
+ clif_item_identify_list(sd);
+ break;
+
+ case BS_REPAIRWEAPON: /* 武器修理 */
+ if(sd)
+//動作しないのでとりあえずコメントアウト
+// clif_item_repair_list(sd);
+ break;
+
+ case MC_VENDING: /* 露店開設 */
+ if(sd)
+ clif_openvendingreq(sd,2+sd->skilllv);
+ break;
+
+ case AL_TELEPORT: /* テレポート */
+ if( sd ){
+ if(map[sd->bl.m].flag.noteleport){ /* テレポ禁止 */
+ clif_skill_teleportmessage(sd,0);
+ break;
+ }
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if( sd->skilllv==1 )
+ clif_skill_warppoint(sd,sd->skillid,"Random","","","");
+ else{
+ clif_skill_warppoint(sd,sd->skillid,"Random",
+ sd->status.save_point.map,"","");
+ }
+ }else if( bl->type==BL_MOB )
+ mob_warp((struct mob_data *)bl,-1,-1,-1,3);
+ break;
+
+ case AL_HOLYWATER: /* アクアベネディクタ */
+ if(sd) {
+ int eflag;
+ struct item item_tmp;
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ memset(&item_tmp,0,sizeof(item_tmp));
+ item_tmp.nameid = 523;
+ item_tmp.identify = 1;
+ if(battle_config.holywater_name_input) {
+ item_tmp.card[0] = 0xfe;
+ item_tmp.card[1] = 0;
+ *((unsigned long *)(&item_tmp.card[2]))=sd->char_id; /* キャラID */
+ }
+ eflag = pc_additem(sd,&item_tmp,1);
+ if(eflag) {
+ clif_additem(sd,0,0,eflag);
+ map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
+ }
+ }
+ break;
+ case TF_PICKSTONE:
+ if(sd) {
+ int eflag;
+ struct item item_tmp;
+ struct block_list tbl;
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ memset(&item_tmp,0,sizeof(item_tmp));
+ memset(&tbl,0,sizeof(tbl)); // [MouseJstr]
+ item_tmp.nameid = 7049;
+ item_tmp.identify = 1;
+ tbl.id = 0;
+ clif_takeitem(&sd->bl,&tbl);
+ eflag = pc_additem(sd,&item_tmp,1);
+ if(eflag) {
+ clif_additem(sd,0,0,eflag);
+ map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
+ }
+ }
+ break;
+
+ case RG_STRIPWEAPON: /* ストリップウェポン */
+ {
+ struct status_change *tsc_data = battle_get_sc_data(bl);
+
+ if(tsc_data && tsc_data[SC_CP_WEAPON].timer != -1 )
+ break;
+ strip_per = 5+2*skilllv+strip_fix/5;
+ strip_time = skill_get_time(skillid,skilllv)+strip_fix/2;
+ if(rand()%100 < strip_per){
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,strip_time,0 );
+ if(dstsd){
+ for(i=0;i<MAX_INVENTORY;i++){
+ if(dstsd->status.inventory[i].equip && dstsd->status.inventory[i].equip & 0x0002){
+ pc_unequipitem(dstsd,i,0);
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case RG_STRIPSHIELD: /* ストリップシールド */
+ {
+ struct status_change *tsc_data = battle_get_sc_data(bl);
+
+ if(tsc_data && tsc_data[SC_CP_SHIELD].timer != -1 )
+ break;
+ strip_per = 5+2*skilllv+strip_fix/5;
+ strip_time = skill_get_time(skillid,skilllv)+strip_fix/2;
+ if(rand()%100 < strip_per){
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,strip_time,0 );
+ if(dstsd){
+ for(i=0;i<MAX_INVENTORY;i++){
+ if(dstsd->status.inventory[i].equip && dstsd->status.inventory[i].equip & 0x0020){
+ pc_unequipitem(dstsd,i,0);
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case RG_STRIPARMOR: /* ストリップアーマー */
+ {
+ struct status_change *tsc_data = battle_get_sc_data(bl);
+
+ if(tsc_data && tsc_data[SC_CP_ARMOR].timer != -1 )
+ break;
+ strip_per = 5+2*skilllv+strip_fix/5;
+ strip_time = skill_get_time(skillid,skilllv)+strip_fix/2;
+ if(rand()%100 < strip_per){
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,strip_time,0 );
+ if(dstsd){
+ for(i=0;i<MAX_INVENTORY;i++){
+ if(dstsd->status.inventory[i].equip && dstsd->status.inventory[i].equip & 0x0010){
+ pc_unequipitem(dstsd,i,0);
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case RG_STRIPHELM: /* ストリップヘルム */
+ {
+ struct status_change *tsc_data = battle_get_sc_data(bl);
+
+ if(tsc_data && tsc_data[SC_CP_HELM].timer != -1 )
+ break;
+ strip_per = 5+2*skilllv+strip_fix/5;
+ strip_time = skill_get_time(skillid,skilllv)+strip_fix/2;
+ if(rand()%100 < strip_per){
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,strip_time,0 );
+ if(dstsd){
+ for(i=0;i<MAX_INVENTORY;i++){
+ if(dstsd->status.inventory[i].equip && dstsd->status.inventory[i].equip & 0x0100){
+ pc_unequipitem(dstsd,i,0);
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+ /* PotionPitcher */
+ case AM_POTIONPITCHER: /* ポーションピッチャー */
+ {
+ struct block_list tbl;
+ int i,x,hp = 0,sp = 0;
+ if(sd) {
+ if(sd==dstsd) { // cancel use on oneself
+ map_freeblock_unlock();
+ return 1;
+ }
+ x = skilllv%11 - 1;
+ i = pc_search_inventory(sd,skill_db[skillid].itemid[x]);
+ if(i < 0 || skill_db[skillid].itemid[x] <= 0) {
+ clif_skill_fail(sd,skillid,0,0);
+ map_freeblock_unlock();
+ return 1;
+ }
+ if(sd->inventory_data[i] == NULL || sd->status.inventory[i].amount < skill_db[skillid].amount[x]) {
+ clif_skill_fail(sd,skillid,0,0);
+ map_freeblock_unlock();
+ return 1;
+ }
+ sd->state.potionpitcher_flag = 1;
+ sd->potion_hp = sd->potion_sp = sd->potion_per_hp = sd->potion_per_sp = 0;
+ sd->skilltarget = bl->id;
+ run_script(sd->inventory_data[i]->use_script,0,sd->bl.id,0);
+ pc_delitem(sd,i,skill_db[skillid].amount[x],0);
+ sd->state.potionpitcher_flag = 0;
+ if(sd->potion_per_hp > 0 || sd->potion_per_sp > 0) {
+ hp = battle_get_max_hp(bl) * sd->potion_per_hp / 100;
+ hp = hp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)/100;
+ if(dstsd) {
+ sp = dstsd->status.max_sp * sd->potion_per_sp / 100;
+ sp = sp * (100 + pc_checkskill(sd,AM_POTIONPITCHER) + pc_checkskill(sd,AM_LEARNINGPOTION)*5)/100;
+ }
+ }
+ else {
+ if(sd->potion_hp > 0) {
+ hp = sd->potion_hp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)/100;
+ hp = hp * (100 + (battle_get_vit(bl)<<1)) / 100;
+ if(dstsd)
+ hp = hp * (100 + pc_checkskill(dstsd,SM_RECOVERY)*10) / 100;
+ }
+ if(sd->potion_sp > 0) {
+ sp = sd->potion_sp * (100 + pc_checkskill(sd,AM_POTIONPITCHER) + pc_checkskill(sd,AM_LEARNINGPOTION)*5)/100;
+ sp = sp * (100 + (battle_get_int(bl)<<1)) / 100;
+ if(dstsd)
+ sp = sp * (100 + pc_checkskill(dstsd,MG_SRECOVERY)*10) / 100;
+ }
+ }
+ }
+ else {
+ hp = (1 + rand()%400) * (100 + skilllv*10) / 100;
+ hp = hp * (100 + (battle_get_vit(bl)<<1)) / 100;
+ if(dstsd)
+ hp = hp * (100 + pc_checkskill(dstsd,SM_RECOVERY)*10) / 100;
+ }
+ tbl.id = 0;
+ tbl.m = src->m;
+ tbl.x = src->x;
+ tbl.y = src->y;
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if(hp > 0 || (hp <= 0 && sp <= 0))
+ clif_skill_nodamage(&tbl,bl,AL_HEAL,hp,1);
+ if(sp > 0)
+ clif_skill_nodamage(&tbl,bl,MG_SRECOVERY,sp,1);
+ battle_heal(src,bl,hp,sp,0);
+ }
+ break;
+ case AM_CP_WEAPON:
+ {
+ struct status_change *tsc_data = battle_get_sc_data(bl);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if(tsc_data && tsc_data[SC_STRIPWEAPON].timer != -1)
+ skill_status_change_end(bl, SC_STRIPWEAPON, -1 );
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+ }
+ break;
+ case AM_CP_SHIELD:
+ {
+ struct status_change *tsc_data = battle_get_sc_data(bl);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if(tsc_data && tsc_data[SC_STRIPSHIELD].timer != -1)
+ skill_status_change_end(bl, SC_STRIPSHIELD, -1 );
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+ }
+ break;
+ case AM_CP_ARMOR:
+ {
+ struct status_change *tsc_data = battle_get_sc_data(bl);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if(tsc_data && tsc_data[SC_STRIPARMOR].timer != -1)
+ skill_status_change_end(bl, SC_STRIPARMOR, -1 );
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+ }
+ break;
+ case AM_CP_HELM:
+ {
+ struct status_change *tsc_data = battle_get_sc_data(bl);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if(tsc_data && tsc_data[SC_STRIPHELM].timer != -1)
+ skill_status_change_end(bl, SC_STRIPHELM, -1 );
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+ }
+ break;
+ case SA_DISPELL: /* ディスペル */
+ {
+ int i;
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
+ break;
+ for(i=0;i<136;i++){
+ if(i==SC_RIDING || i== SC_FALCON || i==SC_HALLUCINATION || i==SC_WEIGHT50
+ || i==SC_WEIGHT90 || i==SC_STRIPWEAPON || i==SC_STRIPSHIELD || i==SC_STRIPARMOR
+ || i==SC_STRIPHELM || i==SC_CP_WEAPON || i==SC_CP_SHIELD || i==SC_CP_ARMOR
+ || i==SC_CP_HELM || i==SC_COMBO)
+ continue;
+ skill_status_change_end(bl,i,-1);
+ }
+ }
+ break;
+
+ case TF_BACKSLIDING: /* バックステップ */
+ battle_stopwalking(src,1);
+ skill_blown(src,bl,skill_get_blewcount(skillid,skilllv)|0x10000);
+ if(src->type == BL_MOB)
+ clif_fixmobpos((struct mob_data *)src);
+ else if(src->type == BL_PET)
+ clif_fixpetpos((struct pet_data *)src);
+ else if(src->type == BL_PC)
+ clif_fixpos(src);
+ skill_addtimerskill(src,tick + 200,src->id,0,0,skillid,skilllv,0,flag);
+ break;
+
+ case SA_CASTCANCEL:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_castcancel(src,1);
+ if(sd) {
+ int sp = skill_get_sp(sd->skillid_old,sd->skilllv_old);
+ sp = sp * (90 - (skilllv-1)*20) / 100;
+ if(sp < 0) sp = 0;
+ pc_heal(sd,0,-sp);
+ }
+ break;
+ case SA_SPELLBREAKER: // スペルブレイカー
+ {
+ struct status_change *sc_data = battle_get_sc_data(bl);
+ int sp;
+ if(sc_data && sc_data[SC_MAGICROD].timer != -1) {
+ if(dstsd) {
+ sp = skill_get_sp(skillid,skilllv);
+ sp = sp * sc_data[SC_MAGICROD].val2 / 100;
+ if(sp > 0x7fff) sp = 0x7fff;
+ else if(sp < 1) sp = 1;
+ if(dstsd->status.sp + sp > dstsd->status.max_sp) {
+ sp = dstsd->status.max_sp - dstsd->status.sp;
+ dstsd->status.sp = dstsd->status.max_sp;
+ }
+ else
+ dstsd->status.sp += sp;
+ clif_heal(dstsd->fd,SP_SP,sp);
+ }
+ clif_skill_nodamage(bl,bl,SA_MAGICROD,sc_data[SC_MAGICROD].val1,1);
+ if(sd) {
+ sp = sd->status.max_sp/5;
+ if(sp < 1) sp = 1;
+ pc_heal(sd,0,-sp);
+ }
+ }
+ else {
+ int bl_skillid=0,bl_skilllv=0;
+ if(bl->type == BL_PC) {
+ if(dstsd && dstsd->skilltimer != -1) {
+ bl_skillid = dstsd->skillid;
+ bl_skilllv = dstsd->skilllv;
+ }
+ }
+ else if(bl->type == BL_MOB) {
+ if(dstmd && dstmd->skilltimer != -1) {
+ bl_skillid = dstmd->skillid;
+ bl_skilllv = dstmd->skilllv;
+ }
+ }
+ if(bl_skillid > 0 && skill_db[bl_skillid].skill_type == BF_MAGIC) {
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_castcancel(bl,0);
+ sp = skill_get_sp(bl_skillid,bl_skilllv);
+ if(dstsd)
+ pc_heal(dstsd,0,-sp);
+ if(sd) {
+ sp = sp*(25*(skilllv-1))/100;
+ if(skilllv > 1 && sp < 1) sp = 1;
+ if(sp > 0x7fff) sp = 0x7fff;
+ else if(sp < 1) sp = 1;
+ if(sd->status.sp + sp > sd->status.max_sp) {
+ sp = sd->status.max_sp - sd->status.sp;
+ sd->status.sp = sd->status.max_sp;
+ }
+ else
+ sd->status.sp += sp;
+ clif_heal(sd->fd,SP_SP,sp);
+ }
+ }
+ else if(sd)
+ clif_skill_fail(sd,skillid,0,0);
+ }
+ }
+ break;
+ case SA_MAGICROD:
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
+ break;
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+ break;
+ case SA_AUTOSPELL: /* オートスペル */
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if(sd)
+ clif_autospell(sd,skilllv);
+ else {
+ int maxlv=1,spellid=0;
+ static const int spellarray[3] = { MG_COLDBOLT,MG_FIREBOLT,MG_LIGHTNINGBOLT };
+ if(skilllv >= 10) {
+ spellid = MG_FROSTDIVER;
+ maxlv = skilllv - 9;
+ }
+ else if(skilllv >=8) {
+ spellid = MG_FIREBALL;
+ maxlv = skilllv - 7;
+ }
+ else if(skilllv >=5) {
+ spellid = MG_SOULSTRIKE;
+ maxlv = skilllv - 4;
+ }
+ else if(skilllv >=2) {
+ int i = rand()%3;
+ spellid = spellarray[i];
+ maxlv = skilllv - 1;
+ }
+ else if(skilllv > 0) {
+ spellid = MG_NAPALMBEAT;
+ maxlv = 3;
+ }
+ if(spellid > 0)
+ skill_status_change_start(src,SC_AUTOSPELL,skilllv,spellid,maxlv,0,
+ skill_get_time(SA_AUTOSPELL,skilllv),0);
+ }
+ break;
+
+ /* ランダム属性変化、水属性変化、地、火、風 */
+ case NPC_ATTRICHANGE:
+ case NPC_CHANGEWATER:
+ case NPC_CHANGEGROUND:
+ case NPC_CHANGEFIRE:
+ case NPC_CHANGEWIND:
+ /* 毒、聖、念、闇 */
+ case NPC_CHANGEPOISON:
+ case NPC_CHANGEHOLY:
+ case NPC_CHANGEDARKNESS:
+ case NPC_CHANGETELEKINESIS:
+ if(md){
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ md->def_ele=skill_get_pl(skillid);
+ if(md->def_ele==0) /* ランダム変化、ただし、*/
+ md->def_ele=rand()%10; /* 不死属性は除く */
+ md->def_ele+=(1+rand()%4)*20; /* 属性レベルはランダム */
+ }
+ break;
+
+ case NPC_PROVOCATION:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if(md)
+ clif_pet_performance(src,mob_db[md->class].skill[md->skillidx].val[0]);
+ break;
+
+ case NPC_HALLUCINATION:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
+ break;
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+ break;
+
+ case NPC_KEEPING:
+ case NPC_BARRIER:
+ {
+ int skill_time = skill_get_time(skillid,skilllv);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_time,0 );
+ mob_changestate((struct mob_data *)src,MS_DELAY,skill_time);
+ }
+ break;
+
+ case NPC_DARKBLESSING:
+ {
+ int sc_def = 100 - battle_get_mdef(bl);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
+ break;
+ if(battle_get_elem_type(bl) == 7 || battle_get_race(bl) == 6)
+ break;
+ if(rand()%100 < sc_def*(50+skilllv*5)/100) {
+ if(dstsd) {
+ int hp = battle_get_hp(bl)-1;
+ pc_heal(dstsd,-hp,0);
+ }
+ else if(dstmd)
+ dstmd->hp = 1;
+ }
+ }
+ break;
+
+ case NPC_SELFDESTRUCTION: /* 自爆 */
+ case NPC_SELFDESTRUCTION2: /* 自爆2 */
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,skillid,0,0,skill_get_time(skillid,skilllv),0);
+ break;
+ case NPC_LICK:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_weapon_damage )
+ break;
+ if(dstsd)
+ pc_heal(dstsd,0,-100);
+ if(rand()%100 < (skilllv*5)*sc_def_vit/100)
+ skill_status_change_start(bl,SC_STAN,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+ break;
+
+ case NPC_SUICIDE: /* 自決 */
+ if(src && bl && md){
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ mob_damage(NULL,md,md->hp,0);
+ }
+ break;
+
+ case NPC_SUMMONSLAVE: /* 手下召喚 */
+ case NPC_SUMMONMONSTER: /* MOB召喚 */
+ if(md && !md->master_id){
+ mob_summonslave(md,mob_db[md->class].skill[md->skillidx].val,skilllv,(skillid==NPC_SUMMONSLAVE)?1:0);
+ }
+ break;
+
+ case NPC_TRANSFORMATION:
+ case NPC_METAMORPHOSIS:
+ if(md)
+ mob_class_change(md,mob_db[md->class].skill[md->skillidx].val);
+ break;
+
+ case NPC_EMOTION: /* エモーション */
+ if(md)
+ clif_emotion(&md->bl,mob_db[md->class].skill[md->skillidx].val[0]);
+ break;
+
+ case NPC_DEFENDER:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ break;
+
+ case WE_MALE: /* 君だけは護るよ */
+ if(sd && dstsd){
+ int hp_rate=(skilllv <= 0)? 0:skill_db[skillid].hp_rate[skilllv-1];
+ int gain_hp=sd->status.max_hp*abs(hp_rate)/100;// 15%
+ clif_skill_nodamage(src,bl,skillid,gain_hp,1);
+ battle_heal(NULL,bl,gain_hp,0,0);
+ }
+ break;
+ case WE_FEMALE: /* あなたの為に犠牲になります */
+ if(sd && dstsd){
+ int sp_rate=(skilllv <= 0)? 0:skill_db[skillid].sp_rate[skilllv-1];
+ int gain_sp=sd->status.max_sp*abs(sp_rate)/100;// 15%
+ clif_skill_nodamage(src,bl,skillid,gain_sp,1);
+ battle_heal(NULL,bl,0,gain_sp,0);
+ }
+ break;
+
+ case WE_CALLPARTNER: /* あなたに会いたい */
+ if(sd && dstsd){
+ if(map[sd->bl.m].flag.nomemo){
+ clif_skill_teleportmessage(sd,1);
+ return 0;
+ }
+ if((dstsd = pc_get_partner(sd)) == NULL){
+ clif_skill_fail(sd,skillid,0,0);
+ return 0;
+ }
+ skill_unitsetting(src,skillid,skilllv,sd->bl.x,sd->bl.y,0);
+ }
+ break;
+
+ case PF_HPCONVERSION: /* ライフ置き換え */
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if(sd){
+ int conv_hp=0,conv_sp=0;
+ conv_hp=sd->status.hp/10; //基本はHPの10%
+ sd->status.hp -= conv_hp; //HPを減らす
+ conv_sp=conv_hp*20*skilllv/100;
+ conv_sp=(sd->status.sp+conv_sp>sd->status.max_sp)?sd->status.max_sp-sd->status.sp:conv_sp;
+ sd->status.sp += conv_sp; //SPを増やす
+ pc_heal(sd,-conv_hp,conv_sp);
+ clif_heal(sd->fd,SP_SP,conv_sp);
+ }
+ break;
+ case HT_REMOVETRAP: /* リムーブトラップ */
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ {
+ struct skill_unit *su=NULL;
+ struct item item_tmp;
+ int flag;
+ if((bl->type==BL_SKILL) &&
+ (su=(struct skill_unit *)bl) &&
+ (su->group->src_id == src->id || map[bl->m].flag.pvp || map[bl->m].flag.gvg) &&
+ (su->group->unit_id >= 0x8f && su->group->unit_id <= 0x99) &&
+ (su->group->unit_id != 0x92)){ //罠を取り返す
+ if(sd){
+ if(battle_config.skill_removetrap_type == 1){
+ for(i=0;i<10;i++) {
+ if(skill_db[su->group->skill_id].itemid[i] > 0){
+ memset(&item_tmp,0,sizeof(item_tmp));
+ item_tmp.nameid = skill_db[su->group->skill_id].itemid[i];
+ item_tmp.identify = 1;
+ if(item_tmp.nameid && (flag=pc_additem(sd,&item_tmp,skill_db[su->group->skill_id].amount[i]))){
+ clif_additem(sd,0,0,flag);
+ map_addflooritem(&item_tmp,skill_db[su->group->skill_id].amount[i],sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
+ }
+ }
+ }
+ }else{
+ memset(&item_tmp,0,sizeof(item_tmp));
+ item_tmp.nameid = 1065;
+ item_tmp.identify = 1;
+ if(item_tmp.nameid && (flag=pc_additem(sd,&item_tmp,1))){
+ clif_additem(sd,0,0,flag);
+ map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
+ }
+ }
+
+ }
+ if(su->group->unit_id == 0x91 && su->group->val2){
+ struct block_list *target=map_id2bl(su->group->val2);
+ if(target && (target->type == BL_PC || target->type == BL_MOB))
+ skill_status_change_end(target,SC_ANKLE,-1);
+ }
+ skill_delunit(su);
+ }
+ }
+ break;
+ case HT_SPRINGTRAP: /* スプリングトラップ */
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ {
+ struct skill_unit *su=NULL;
+ if((bl->type==BL_SKILL) && (su=(struct skill_unit *)bl) && (su->group) ){
+ switch(su->group->unit_id){
+ case 0x8f: /* ブラストマイン */
+ case 0x90: /* スキッドトラップ */
+ case 0x93: /* ランドマイン */
+ case 0x94: /* ショックウェーブトラップ */
+ case 0x95: /* サンドマン */
+ case 0x96: /* フラッシャー */
+ case 0x97: /* フリージングトラップ */
+ case 0x98: /* クレイモアートラップ */
+ case 0x99: /* トーキーボックス */
+ su->group->unit_id = 0x8c;
+ clif_changelook(bl,LOOK_BASE,su->group->unit_id);
+ su->group->limit=DIFF_TICK(tick+1500,su->group->tick);
+ su->limit=DIFF_TICK(tick+1500,su->group->tick);
+ }
+ }
+ }
+ break;
+ case BD_ENCORE: /* アンコール */
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if(sd)
+ skill_use_id(sd,src->id,sd->skillid_dance,sd->skilllv_dance);
+ break;
+ case AS_SPLASHER: /* ベナムスプラッシャー */
+ if((double)battle_get_max_hp(bl)*2/3 < battle_get_hp(bl)) //HPが2/3以上残っていたら失敗
+ return 1;
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,skillid,src->id,0,skill_get_time(skillid,skilllv),0 );
+ break;
+ case PF_MINDBREAKER: /* プロボック */
+ {
+ struct status_change *sc_data = battle_get_sc_data(bl);
+
+ /* MVPmobと不死には効かない */
+ if((bl->type==BL_MOB && battle_get_mode(bl)&0x20) || battle_check_undead(battle_get_race(bl),battle_get_elem_type(bl))) //不死には効かない
+ {
+ map_freeblock_unlock();
+ return 1;
+ }
+
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
+
+ if(dstmd && dstmd->skilltimer!=-1 && dstmd->state.skillcastcancel) // 詠唱妨害
+ skill_castcancel(bl,0);
+ if(dstsd && dstsd->skilltimer!=-1 && (!dstsd->special_state.no_castcancel || map[bl->m].flag.gvg)
+ && dstsd->state.skillcastcancel && !dstsd->special_state.no_castcancel2)
+ skill_castcancel(bl,0);
+
+ if(sc_data){
+ if(sc_data[SC_FREEZE].timer!=-1)
+ skill_status_change_end(bl,SC_FREEZE,-1);
+ if(sc_data[SC_STONE].timer!=-1 && sc_data[SC_STONE].val2==0)
+ skill_status_change_end(bl,SC_STONE,-1);
+ if(sc_data[SC_SLEEP].timer!=-1)
+ skill_status_change_end(bl,SC_SLEEP,-1);
+ }
+
+ if(bl->type==BL_MOB) {
+ int range = skill_get_range(skillid,skilllv);
+ if(range < 0)
+ range = battle_get_range(src) - (range + 1);
+ mob_target((struct mob_data *)bl,src,range);
+ }
+ }
+ break;
+
+
+
+
+
+
+ case RG_CLEANER: //AppleGirl
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ {
+ struct skill_unit *su=NULL;
+ if((bl->type==BL_SKILL) &&
+ (su=(struct skill_unit *)bl) &&
+ (su->group->src_id == src->id || map[bl->m].flag.pvp || map[bl->m].flag.gvg) &&
+ (su->group->unit_id == 0xb0)){ //罠を取り返す
+ if(sd)
+ skill_delunit(su);
+ }
+ }
+ break;
+ default:
+ printf("Unknown skill used:%d\n",skillid);
+ map_freeblock_unlock();
+ return 1;
+ }
+
+ map_freeblock_unlock();
+ return 0;
+}
+
+/*==========================================
+ * スキル使用(詠唱完了、ID指定)
+ *------------------------------------------
+ */
+int skill_castend_id( int tid, unsigned int tick, int id,int data )
+{
+ struct map_session_data* sd = map_id2sd(id)/*,*target_sd=NULL*/;
+ struct block_list *bl;
+ int range,inf2;
+
+ nullpo_retr(0, sd);
+
+ if( sd->bl.prev == NULL ) //prevが無いのはありなの?
+ return 0;
+
+ if(sd->skillid != SA_CASTCANCEL && sd->skilltimer != tid ) /* タイマIDの確認 */
+ return 0;
+ if(sd->skillid != SA_CASTCANCEL && sd->skilltimer != -1 && pc_checkskill(sd,SA_FREECAST) > 0) {
+ sd->speed = sd->prev_speed;
+ clif_updatestatus(sd,SP_SPEED);
+ }
+ if(sd->skillid != SA_CASTCANCEL)
+ sd->skilltimer=-1;
+
+ if((bl=map_id2bl(sd->skilltarget))==NULL || bl->prev==NULL) {
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+ if(sd->bl.m != bl->m || pc_isdead(sd)) { //マップが違うか自分が死んでいる
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+
+ if(sd->skillid == PR_LEXAETERNA) {
+ struct status_change *sc_data = battle_get_sc_data(bl);
+ if(sc_data && (sc_data[SC_FREEZE].timer != -1 || (sc_data[SC_STONE].timer != -1 && sc_data[SC_STONE].val2 == 0))) {
+ clif_skill_fail(sd,sd->skillid,0,0);
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+ }
+ else if(sd->skillid == RG_BACKSTAP) {
+ int dir = map_calc_dir(&sd->bl,bl->x,bl->y),t_dir = battle_get_dir(bl);
+ int dist = distance(sd->bl.x,sd->bl.y,bl->x,bl->y);
+ if(bl->type != BL_SKILL && (dist == 0 || map_check_dir(dir,t_dir))) {
+ clif_skill_fail(sd,sd->skillid,0,0);
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+ }
+
+ inf2 = skill_get_inf2(sd->skillid);
+ if( ( (skill_get_inf(sd->skillid)&1) || inf2&4 ) && // 彼我敵対関係チェック
+ battle_check_target(&sd->bl,bl, BCT_ENEMY)<=0 ) {
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+ if(inf2 & 0xC00 && sd->bl.id != bl->id) {
+ int fail_flag = 1;
+ if(inf2 & 0x400 && battle_check_target(&sd->bl,bl, BCT_PARTY) > 0)
+ fail_flag = 0;
+ if(inf2 & 0x800 && sd->status.guild_id > 0 && sd->status.guild_id == battle_get_guild_id(bl))
+ fail_flag = 0;
+ if(fail_flag) {
+ clif_skill_fail(sd,sd->skillid,0,0);
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+ }
+
+ range = skill_get_range(sd->skillid,sd->skilllv);
+ if(range < 0)
+ range = battle_get_range(&sd->bl) - (range + 1);
+ range += battle_config.pc_skill_add_range;
+ if((sd->skillid == MO_EXTREMITYFIST && sd->sc_data[SC_COMBO].timer != -1 && sd->sc_data[SC_COMBO].val1 == MO_COMBOFINISH) ||
+ (sd->skillid == CH_TIGERFIST && sd->sc_data[SC_COMBO].timer != -1 && sd->sc_data[SC_COMBO].val1 == MO_COMBOFINISH) ||
+ (sd->skillid == CH_CHAINCRUSH && sd->sc_data[SC_COMBO].timer != -1 && sd->sc_data[SC_COMBO].val1 == MO_COMBOFINISH) ||
+ (sd->skillid == CH_CHAINCRUSH && sd->sc_data[SC_COMBO].timer != -1 && sd->sc_data[SC_COMBO].val1 == CH_TIGERFIST))
+ range += skill_get_blewcount(MO_COMBOFINISH,sd->sc_data[SC_COMBO].val2);
+ if(battle_config.skill_out_range_consume) { // changed to allow casting when target walks out of range [Valaris]
+ if(range < distance(sd->bl.x,sd->bl.y,bl->x,bl->y)) {
+ clif_skill_fail(sd,sd->skillid,0,0);
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+ }
+ if(!skill_check_condition(sd,1)) { /* 使用条件チェック */
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+ sd->skillitem = sd->skillitemlv = -1;
+ if(battle_config.skill_out_range_consume) {
+ if(range < distance(sd->bl.x,sd->bl.y,bl->x,bl->y)) {
+ clif_skill_fail(sd,sd->skillid,0,0);
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ return 0;
+ }
+ }
+
+ if(battle_config.pc_skill_log)
+ printf("PC %d skill castend skill=%d\n",sd->bl.id,sd->skillid);
+ pc_stop_walking(sd,0);
+
+ switch( skill_get_nk(sd->skillid) )
+ {
+ /* 攻撃系/吹き飛ばし系 */
+ case 0: case 2:
+ skill_castend_damage_id(&sd->bl,bl,sd->skillid,sd->skilllv,tick,0);
+ break;
+ case 1:/* 支援系 */
+ if( (sd->skillid==AL_HEAL || (sd->skillid==ALL_RESURRECTION && bl->type != BL_PC) || sd->skillid==PR_ASPERSIO) && battle_check_undead(battle_get_race(bl),battle_get_elem_type(bl)))
+ skill_castend_damage_id(&sd->bl,bl,sd->skillid,sd->skilllv,tick,0);
+ else
+ skill_castend_nodamage_id(&sd->bl,bl,sd->skillid,sd->skilllv,tick,0);
+ break;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * スキル使用(詠唱完了、場所指定の実際の処理)
+ *------------------------------------------
+ */
+int skill_castend_pos2( struct block_list *src, int x,int y,int skillid,int skilllv,unsigned int tick,int flag)
+{
+ struct map_session_data *sd=NULL;
+ int i,tmpx = 0,tmpy = 0, x1 = 0, y1 = 0;
+
+ nullpo_retr(0, src);
+
+ if(src->type==BL_PC){
+ nullpo_retr(0, sd=(struct map_session_data *)src);
+ }
+ if( skillid != WZ_METEOR &&
+ skillid != WZ_SIGHTRASHER &&
+ skillid != AM_CANNIBALIZE &&
+ skillid != AM_SPHEREMINE)
+ clif_skill_poseffect(src,skillid,skilllv,x,y,tick);
+
+ if (skillnotok(skillid, sd)) // [MouseJstr]
+ return 0;
+
+ switch(skillid)
+ {
+ case PR_BENEDICTIO: /* 聖体降福 */
+ skill_area_temp[1]=src->id;
+ map_foreachinarea(skill_area_sub,
+ src->m,x-1,y-1,x+1,y+1,0,
+ src,skillid,skilllv,tick, flag|BCT_NOENEMY|1,
+ skill_castend_nodamage_id);
+ map_foreachinarea(skill_area_sub,
+ src->m,x-1,y-1,x+1,y+1,0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
+ skill_castend_damage_id);
+ break;
+
+ case BS_HAMMERFALL: /* ハンマーフォール */
+ skill_area_temp[1]=src->id;
+ skill_area_temp[2]=x;
+ skill_area_temp[3]=y;
+ map_foreachinarea(skill_area_sub,
+ src->m,x-2,y-2,x+2,y+2,0,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY|2,
+ skill_castend_nodamage_id);
+ break;
+
+ case HT_DETECTING: /* ディテクティング */
+ {
+ const int range=7;
+ map_foreachinarea( skill_status_change_timer_sub,
+ src->m, src->x-range, src->y-range, src->x+range,src->y+range,0,
+ src,SC_SIGHT,tick);
+ }
+ break;
+
+ case MG_SAFETYWALL: /* セイフティウォール */
+ case MG_FIREWALL: /* ファイヤーウォール */
+ case MG_THUNDERSTORM: /* サンダーストーム */
+ case AL_PNEUMA: /* ニューマ */
+ case WZ_ICEWALL: /* アイスウォール */
+ case WZ_FIREPILLAR: /* ファイアピラー */
+ case WZ_SIGHTRASHER:
+ case WZ_QUAGMIRE: /* クァグマイア */
+ case WZ_VERMILION: /* ロードオブヴァーミリオン */
+ case WZ_FROSTNOVA: /* フロストノヴァ */
+ case WZ_STORMGUST: /* ストームガスト */
+ case WZ_HEAVENDRIVE: /* ヘヴンズドライブ */
+ case PR_SANCTUARY: /* サンクチュアリ */
+ case PR_MAGNUS: /* マグヌスエクソシズム */
+ case CR_GRANDCROSS: /* グランドクロス */
+ case HT_SKIDTRAP: /* スキッドトラップ */
+ case HT_LANDMINE: /* ランドマイン */
+ case HT_ANKLESNARE: /* アンクルスネア */
+ case HT_SHOCKWAVE: /* ショックウェーブトラップ */
+ case HT_SANDMAN: /* サンドマン */
+ case HT_FLASHER: /* フラッシャー */
+ case HT_FREEZINGTRAP: /* フリージングトラップ */
+ case HT_BLASTMINE: /* ブラストマイン */
+ case HT_CLAYMORETRAP: /* クレイモアートラップ */
+ case AS_VENOMDUST: /* ベノムダスト */
+ case AM_DEMONSTRATION: /* デモンストレーション */
+ case PF_SPIDERWEB: /* スパイダーウェッブ */
+ case PF_FOGWALL: /* フォグウォール */
+ case HT_TALKIEBOX: /* トーキーボックス */
+ skill_unitsetting(src,skillid,skilllv,x,y,0);
+ break;
+
+ case RG_GRAFFITI: /* Graffiti [Valaris] */
+ skill_clear_unitgroup(src);
+ skill_unitsetting(src,skillid,skilllv,x,y,0);
+ break;
+
+ case SA_VOLCANO: /* ボルケーノ */
+ case SA_DELUGE: /* デリュージ */
+ case SA_VIOLENTGALE: /* バイオレントゲイル */
+ case SA_LANDPROTECTOR: /* ランドプロテクター */
+ skill_clear_element_field(src);//既に自分が発動している属性場をクリア
+ skill_unitsetting(src,skillid,skilllv,x,y,0);
+ break;
+
+ case WZ_METEOR: //メテオストーム
+ {
+ int flag=0;
+ for(i=0;i<2+(skilllv>>1);i++) {
+ int j=0, c;
+ do {
+ tmpx = x + (rand()%7 - 3);
+ tmpy = y + (rand()%7 - 3);
+ if(tmpx < 0)
+ tmpx = 0;
+ else if(tmpx >= map[src->m].xs)
+ tmpx = map[src->m].xs - 1;
+ if(tmpy < 0)
+ tmpy = 0;
+ else if(tmpy >= map[src->m].ys)
+ tmpy = map[src->m].ys - 1;
+ j++;
+ } while(((c=map_getcell(src->m,tmpx,tmpy))==1 || c==5) && j<100);
+ if(j >= 100)
+ continue;
+ if(flag==0){
+ clif_skill_poseffect(src,skillid,skilllv,tmpx,tmpy,tick);
+ flag=1;
+ }
+ if(i > 0)
+ skill_addtimerskill(src,tick+i*1000,0,tmpx,tmpy,skillid,skilllv,(x1<<16)|y1,flag);
+ x1 = tmpx;
+ y1 = tmpy;
+ }
+ skill_addtimerskill(src,tick+i*1000,0,tmpx,tmpy,skillid,skilllv,-1,flag);
+ }
+ break;
+
+ case AL_WARP: /* ワープポータル */
+ if(sd) {
+ if(map[sd->bl.m].flag.noteleport) /* テレポ禁止 */
+ break;
+ clif_skill_warppoint(sd,sd->skillid,sd->status.save_point.map,
+ (sd->skilllv>1)?sd->status.memo_point[0].map:"",
+ (sd->skilllv>2)?sd->status.memo_point[1].map:"",
+ (sd->skilllv>3)?sd->status.memo_point[2].map:"");
+ }
+ break;
+ case MO_BODYRELOCATION:
+ if(sd){
+ pc_movepos(sd,x,y);
+ }else if( src->type==BL_MOB )
+ mob_warp((struct mob_data *)src,-1,x,y,0);
+ break;
+ case AM_CANNIBALIZE: // バイオプラント
+ if(sd){
+ int mx,my,id=0;
+ struct mob_data *md;
+
+ mx = x;// + (rand()%10 - 5);
+ my = y;// + (rand()%10 - 5);
+ id=mob_once_spawn(sd,"this",mx,my,"--ja--",1118,1,"");
+ if( (md=(struct mob_data *)map_id2bl(id)) !=NULL ){
+ md->master_id=sd->bl.id;
+ md->hp=2210+skilllv*200;
+ md->state.special_mob_ai=1;
+ md->deletetimer=add_timer(gettick()+skill_get_time(skillid,skilllv),mob_timer_delete,id,0);
+ }
+ clif_skill_poseffect(src,skillid,skilllv,x,y,tick);
+ }
+ break;
+ case AM_SPHEREMINE: // スフィアーマイン
+ if(sd){
+ int mx,my,id=0;
+ struct mob_data *md;
+
+ mx = x;// + (rand()%10 - 5);
+ my = y;// + (rand()%10 - 5);
+ id=mob_once_spawn(sd,"this",mx,my,"--ja--",1142,1,"");
+ if( (md=(struct mob_data *)map_id2bl(id)) !=NULL ){
+ md->master_id=sd->bl.id;
+ md->hp=1000+skilllv*200;
+ md->state.special_mob_ai=2;
+ md->deletetimer=add_timer(gettick()+skill_get_time(skillid,skilllv),mob_timer_delete,id,0);
+ }
+ clif_skill_poseffect(src,skillid,skilllv,x,y,tick);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * スキル使用(詠唱完了、map指定)
+ *------------------------------------------
+ */
+int skill_castend_map( struct map_session_data *sd,int skill_num, const char *map)
+{
+ int x=0,y=0;
+
+ nullpo_retr(0, sd);
+ if( sd->bl.prev == NULL || pc_isdead(sd) )
+ return 0;
+
+ if(skillnotok(skill_num, sd))
+ return 0;
+
+ if( sd->opt1>0 || sd->status.option&2 )
+ return 0;
+ //スキルが使えない状態異常中
+ if(sd->sc_data){
+ if( sd->sc_data[SC_DIVINA].timer!=-1 ||
+ sd->sc_data[SC_ROKISWEIL].timer!=-1 ||
+ sd->sc_data[SC_AUTOCOUNTER].timer != -1 ||
+ sd->sc_data[SC_STEELBODY].timer != -1 ||
+ sd->sc_data[SC_DANCING].timer!=-1 ||
+ sd->sc_data[SC_BERSERK].timer != -1 )
+ return 0;
+ }
+
+ if( skill_num != sd->skillid) /* 不正パケットらしい */
+ return 0;
+
+ pc_stopattack(sd);
+
+ if(battle_config.pc_skill_log)
+ printf("PC %d skill castend skill =%d map=%s\n",sd->bl.id,skill_num,map);
+ pc_stop_walking(sd,0);
+
+ if(strcmp(map,"cancel")==0)
+ return 0;
+
+ switch(skill_num){
+ case AL_TELEPORT: /* テレポート */
+ if(strcmp(map,"Random")==0)
+ pc_randomwarp(sd,3);
+ else
+ pc_setpos(sd,sd->status.save_point.map,
+ sd->status.save_point.x,sd->status.save_point.y,3);
+ break;
+
+ case AL_WARP: /* ワープポータル */
+ {
+ const struct point *p[]={
+ &sd->status.save_point,&sd->status.memo_point[0],
+ &sd->status.memo_point[1],&sd->status.memo_point[2],
+ };
+ struct skill_unit_group *group;
+ int i;
+ int maxcount=0;
+
+ if((maxcount = skill_get_maxcount(sd->skillid)) > 0) {
+ int c;
+ for(i=c=0;i<MAX_SKILLUNITGROUP;i++) {
+ if(sd->skillunit[i].alive_count > 0 && sd->skillunit[i].skill_id == sd->skillid)
+ c++;
+ }
+ if(c >= maxcount) {
+ clif_skill_fail(sd,sd->skillid,0,0);
+ sd->canact_tick = gettick();
+ sd->canmove_tick = gettick();
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+ }
+
+ for(i=0;i<sd->skilllv;i++){
+ if(strcmp(map,p[i]->map)==0){
+ x=p[i]->x;
+ y=p[i]->y;
+ break;
+ }
+ }
+ if(x==0 || y==0) /* 不正パケット? */
+ return 0;
+
+ if(!skill_check_condition(sd,3))
+ return 0;
+ if((group=skill_unitsetting(&sd->bl,sd->skillid,sd->skilllv,sd->skillx,sd->skilly,0))==NULL)
+ return 0;
+ group->valstr=(char *)aCalloc(24,sizeof(char));
+ memcpy(group->valstr,map,24);
+ group->val2=(x<<16)|y;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * スキルユニット設定処理
+ *------------------------------------------
+ */
+struct skill_unit_group *skill_unitsetting( struct block_list *src, int skillid,int skilllv,int x,int y,int flag)
+{
+ struct skill_unit_group *group;
+ int i,count=1,limit=10000,val1=0,val2=0;
+ int target=BCT_ENEMY,interval=1000,range=0;
+ int dir=0,aoe_diameter=0; // -- aoe_diameter (moonsoul) added for sage Area Of Effect skills
+
+ nullpo_retr(0, src);
+
+ switch(skillid){ /* 設定 */
+
+ case MG_SAFETYWALL: /* セイフティウォール */
+ limit=skill_get_time(skillid,skilllv);
+ val2=skilllv+1;
+ interval = -1;
+ target=(battle_config.defnotenemy)?BCT_NOENEMY:BCT_ALL;
+ break;
+
+ case MG_FIREWALL: /* ファイヤーウォール */
+ if(src->x == x && src->y == y)
+ dir = 2;
+ else
+ dir=map_calc_dir(src,x,y);
+ if(dir&1) count=5;
+ else count=3;
+ limit=skill_get_time(skillid,skilllv);
+ val2=4+skilllv;
+ interval=1;
+ break;
+
+ case AL_PNEUMA: /* ニューマ */
+ limit=skill_get_time(skillid,skilllv);
+ interval = -1;
+ target=(battle_config.defnotenemy)?BCT_NOENEMY:BCT_ALL;
+ count = 9;
+ break;
+
+ case AL_WARP: /* ワープポータル */
+ target=BCT_ALL;
+ val1=skilllv+6;
+ if(flag==0)
+ limit=2000;
+ else
+ limit=skill_get_time(skillid,skilllv);
+ break;
+
+ case PR_SANCTUARY: /* サンクチュアリ */
+ count=21;
+ limit=skill_get_time(skillid,skilllv);
+ val1=skilllv+3;
+ val2=(skilllv>6)?777:skilllv*100;
+ target=BCT_ALL;
+ range=1;
+ break;
+
+ case PR_MAGNUS: /* マグヌスエクソシズム */
+ count=33;
+ limit=skill_get_time(skillid,skilllv);
+ interval=3000;
+ break;
+
+ case WZ_FIREPILLAR: /* ファイアーピラー */
+ if(flag==0)
+ limit=skill_get_time(skillid,skilllv);
+ else
+ limit=1000;
+ interval=2000;
+ val1=skilllv+2;
+ range=1;
+ break;
+
+ case MG_THUNDERSTORM: /* サンダーストーム */
+ limit=500;
+ range=1;
+ break;
+
+ case WZ_FROSTNOVA: /* フロストノヴァ */
+ limit=500;
+ range=5;
+ break;
+ case WZ_HEAVENDRIVE: /* ヘヴンズドライブ */
+ limit=500;
+ range=2;
+ break;
+
+ case WZ_METEOR: /* メテオストーム */
+ limit=500;
+ range=3;
+ break;
+
+ case WZ_SIGHTRASHER:
+ limit=500;
+ count=41;
+ break;
+
+ case WZ_VERMILION: /* ロードオブヴァーミリオン */
+ limit=4100;
+ interval=1000;
+ range=6;
+ break;
+
+ case WZ_ICEWALL: /* アイスウォール */
+ limit=skill_get_time(skillid,skilllv);
+ count=5;
+ break;
+
+ case WZ_STORMGUST: /* ストームガスト */
+ limit=4600;
+ interval=450;
+ range=5;
+ break;
+
+ case WZ_QUAGMIRE: /* クァグマイア */
+ limit=skill_get_time(skillid,skilllv);
+ interval=200;
+ count=25;
+ break;
+
+ case HT_SKIDTRAP: /* スキッドトラップ */
+ case HT_LANDMINE: /* ランドマイン */
+ case HT_ANKLESNARE: /* アンクルスネア */
+ case HT_SANDMAN: /* サンドマン */
+ case PF_SPIDERWEB: /* スパイダーウェッブ */
+ case HT_FLASHER: /* フラッシャー */
+ case HT_FREEZINGTRAP: /* フリージングトラップ */
+ case HT_BLASTMINE: /* ブラストマイン */
+ case HT_CLAYMORETRAP: /* クレイモアートラップ */
+ limit=skill_get_time(skillid,skilllv);
+ range=1;
+ break;
+
+ case HT_TALKIEBOX: /* トーキーボックス */
+ limit=skill_get_time(skillid,skilllv);
+ range=1;
+ target=BCT_ALL;
+ break;
+
+ case HT_SHOCKWAVE: /* ショックウェーブトラップ */
+ limit=skill_get_time(skillid,skilllv);
+ range=1;
+ val1=skilllv*15+10;
+ break;
+
+ case AS_VENOMDUST: /* ベノムダスト */
+ limit=skill_get_time(skillid,skilllv);
+ interval=1000;
+ count=5;
+ break;
+
+ case CR_GRANDCROSS: /* グランドクロス */
+ count=29;
+ limit=1000;
+ interval=300;
+ break;
+
+ case SA_VOLCANO: /* ボルケーノ */
+ case SA_DELUGE: /* デリュージ */
+ case SA_VIOLENTGALE: /* バイオレントゲイル */
+ limit=skill_get_time(skillid,skilllv);
+ count=skilllv<=2?25:(skilllv<=4?49:81);
+ target=BCT_ALL;
+ break;
+
+ case SA_LANDPROTECTOR: /* グランドクロス */
+ limit=skill_get_time(skillid,skilllv); // changed to get duration from cast_db (moonsoul)
+ val1=skilllv*15+10;
+ aoe_diameter=skilllv+skilllv%2+5;
+ target=BCT_ALL;
+ count=aoe_diameter*aoe_diameter; // -- this will not function if changed to ^2 (moonsoul)
+ break;
+
+ case BD_LULLABY: /* 子守唄 */
+ case BD_ETERNALCHAOS: /* エターナルカオス */
+ case BD_ROKISWEIL: /* ロキの叫び */
+ count=81;
+ limit=skill_get_time(skillid,skilllv);
+ range=5;
+ target=BCT_ALL;
+ break;
+ case BD_RICHMANKIM:
+ case BD_DRUMBATTLEFIELD: /* 戦太鼓の響き */
+ case BD_RINGNIBELUNGEN: /* ニーベルングの指輪 */
+ case BD_INTOABYSS: /* 深淵の中に */
+ case BD_SIEGFRIED: /* 不死身のジークフリード */
+ count=81;
+ limit=skill_get_time(skillid,skilllv);
+ range=5;
+ target=BCT_PARTY;
+ break;
+
+ case BA_WHISTLE: /* 口笛 */
+ count=49;
+ limit=skill_get_time(skillid,skilllv);
+ range=5;
+ target=BCT_NOENEMY;
+ if(src->type == BL_PC)
+ val1 = (pc_checkskill((struct map_session_data *)src,BA_MUSICALLESSON)+1)>>1;
+ val2 = ((battle_get_agi(src)/10)&0xffff)<<16;
+ val2 |= (battle_get_luk(src)/10)&0xffff;
+ break;
+ case DC_HUMMING: /* ハミング */
+ count=49;
+ limit=skill_get_time(skillid,skilllv);
+ range=5;
+ target=BCT_NOENEMY;
+ if(src->type == BL_PC)
+ val1 = (pc_checkskill((struct map_session_data *)src,DC_DANCINGLESSON)+1)>>1;
+ val2 = battle_get_dex(src)/10;
+ break;
+
+ case BA_DISSONANCE: /* 不協和音 */
+ case DC_UGLYDANCE: /* 自分勝手なダンス */
+ count=49;
+ limit=skill_get_time(skillid,skilllv);
+ range=5;
+ target=BCT_ENEMY;
+ break;
+
+ case DC_DONTFORGETME: /* 私を忘れないで… */
+ count=49;
+ limit=skill_get_time(skillid,skilllv);
+ range=5;
+ target=BCT_ENEMY;
+ if(src->type == BL_PC)
+ val1 = (pc_checkskill((struct map_session_data *)src,DC_DANCINGLESSON)+1)>>1;
+ val2 = ((battle_get_str(src)/20)&0xffff)<<16;
+ val2 |= (battle_get_agi(src)/10)&0xffff;
+ break;
+ case BA_POEMBRAGI: /* ブラギの詩 */
+ count=49;
+ limit=skill_get_time(skillid,skilllv);
+ range=5;
+ target=BCT_NOENEMY;
+ if(src->type == BL_PC)
+ val1 = pc_checkskill((struct map_session_data *)src,BA_MUSICALLESSON);
+ val2 = ((battle_get_dex(src)/10)&0xffff)<<16;
+ val2 |= (battle_get_int(src)/5)&0xffff;
+ break;
+ case BA_APPLEIDUN: /* イドゥンの林檎 */
+ count=49;
+ limit=skill_get_time(skillid,skilllv);
+ range=5;
+ target=BCT_NOENEMY;
+ if(src->type == BL_PC)
+ val1 = ((pc_checkskill((struct map_session_data *)src,BA_MUSICALLESSON))&0xffff)<<16;
+ else
+ val1 = 0;
+ val1 |= (battle_get_vit(src))&0xffff;
+ val2 = 0;//回復用タイムカウンタ(6秒毎に1増加)
+ break;
+ case DC_SERVICEFORYOU: /* サービスフォーユー */
+ count=49;
+ limit=skill_get_time(skillid,skilllv);
+ range=5;
+ target=BCT_PARTY;
+ if(src->type == BL_PC)
+ val1 = (pc_checkskill((struct map_session_data *)src,DC_DANCINGLESSON)+1)>>1;
+ val2 = battle_get_int(src)/10;
+ break;
+ case BA_ASSASSINCROSS: /* 夕陽のアサシンクロス */
+ count=49;
+ limit=skill_get_time(skillid,skilllv);
+ range=5;
+ target=BCT_NOENEMY;
+ if(src->type == BL_PC)
+ val1 = (pc_checkskill((struct map_session_data *)src,BA_MUSICALLESSON)+1)>>1;
+ val2 = battle_get_agi(src)/20;
+ break;
+ case DC_FORTUNEKISS: /* 幸運のキス */
+ count=49;
+ limit=skill_get_time(skillid,skilllv);
+ range=5;
+ target=BCT_NOENEMY;
+ if(src->type == BL_PC)
+ val1 = (pc_checkskill((struct map_session_data *)src,DC_DANCINGLESSON)+1)>>1;
+ val2 = battle_get_luk(src)/10;
+ break;
+ case AM_DEMONSTRATION: /* デモンストレーション */
+ limit=skill_get_time(skillid,skilllv);
+ interval=1000;
+ range=1;
+ target=BCT_ENEMY;
+ break;
+ case WE_CALLPARTNER: /* あなたに逢いたい */
+ limit=skill_get_time(skillid,skilllv);
+ range=-1;
+ break;
+
+ case HP_BASILICA: /* バジリカ */
+ limit=skill_get_time(skillid,skilllv);
+ target=BCT_ALL;
+ range=3;
+ //Fix to prevent the priest from walking while Basilica is up.
+ battle_stopwalking(src,1);
+ skill_status_change_start(src,SC_ANKLE,skilllv,0,0,0,limit,0);
+ break;
+ case PA_GOSPEL: /* ゴスペル */
+ count=49;
+ target=BCT_PARTY;
+ limit=skill_get_time(skillid,skilllv);
+ break;
+ case PF_FOGWALL: /* フォグウォール */
+ count=15;
+ limit=skill_get_time(skillid,skilllv);
+ break;
+ case RG_GRAFFITI: /* Graffiti */
+ count=1; // Leave this at 1 [Valaris]
+ limit=600000; // Time length [Valaris]
+ break;
+ };
+
+ nullpo_retr(NULL, group=skill_initunitgroup(src,count,skillid,skilllv,skill_get_unit_id(skillid,flag&1)));
+ group->limit=limit;
+ group->val1=val1;
+ group->val2=val2;
+ group->target_flag=target;
+ group->interval=interval;
+ group->range=range;
+ if(skillid==HT_TALKIEBOX ||
+ skillid==RG_GRAFFITI){
+ group->valstr=calloc(80, 1);
+ if(group->valstr==NULL){
+ printf("skill_castend_map: out of memory !\n");
+ exit(1);
+ }
+ memcpy(group->valstr,talkie_mes,80);
+ }
+ for(i=0;i<count;i++){
+ struct skill_unit *unit;
+ int ux=x,uy=y,val1=skilllv,val2=0,limit=group->limit,alive=1;
+ int range=group->range;
+ switch(skillid){ /* 設定 */
+ case AL_PNEUMA: /* ニューマ */
+ {
+ static const int dx[9]={-1, 0, 1,-1, 0, 1,-1, 0, 1};
+ static const int dy[9]={-1,-1,-1, 0, 0, 0, 1, 1, 1};
+ ux+=dx[i];
+ uy+=dy[i];
+ }
+ break;
+ case MG_FIREWALL: /* ファイヤーウォール */
+ {
+ if(dir&1){ /* 斜め配置 */
+ static const int dx[][5]={
+ { 1,1,0,0,-1 }, { -1,-1,0,0,1 },
+ },dy[][5]={
+ { 1,0,0,-1,-1 }, { 1,0,0,-1,-1 },
+ };
+ ux+=dx[(dir>>1)&1][i];
+ uy+=dy[(dir>>1)&1][i];
+ }else{ /* 上下配置 */
+ if(dir%4==0) /* 上下 */
+ ux+=i-1;
+ else /* 左右 */
+ uy+=i-1;
+ }
+ val2=group->val2;
+ }
+ break;
+
+ case PR_SANCTUARY: /* サンクチュアリ */
+ {
+ static const int dx[]={
+ -1,0,1, -2,-1,0,1,2, -2,-1,0,1,2, -2,-1,0,1,2, -1,0,1 };
+ static const int dy[]={
+ -2,-2,-2, -1,-1,-1,-1,-1, 0,0,0,0,0, 1,1,1,1,1, 2,2,2, };
+ ux+=dx[i];
+ uy+=dy[i];
+ }
+ break;
+
+ case PR_MAGNUS: /* マグヌスエクソシズム */
+ {
+ static const int dx[]={ -1,0,1, -1,0,1, -3,-2,-1,0,1,2,3,
+ -3,-2,-1,0,1,2,3, -3,-2,-1,0,1,2,3, -1,0,1, -1,0,1, };
+ static const int dy[]={
+ -3,-3,-3, -2,-2,-2, -1,-1,-1,-1,-1,-1,-1,
+ 0,0,0,0,0,0,0, 1,1,1,1,1,1,1, 2,2,2, 3,3,3 };
+ ux+=dx[i];
+ uy+=dy[i];
+ }
+ break;
+
+ case WZ_SIGHTRASHER:
+ {
+ static const int dx[]={
+ -5, 0, 5, -4, 0, 4, -3, 0, 3, -2, 0, 2, -1, 0, 1, -5,-4,-3,-2,-1, 0, 1, 2, 3, 4, 5, -1, 0, 1, -2, 0, 2, -3, 0, 3, -4, 0, 4, -5, 0, 5 };
+ static const int dy[]={
+ -5,-5,-5, -4,-4,-4, -3,-3,-3, -2,-2,-2, -1,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5 };
+ ux+=dx[i];
+ uy+=dy[i];
+ }
+ break;
+
+ case WZ_ICEWALL: /* アイスウォール */
+ {
+ static const int dirx[8]={0,-1,-1,-1,0,1,1,1};
+ static const int diry[8]={1,1,0,-1,-1,-1,0,1};
+ if(skilllv <= 1)
+ val1 = 500;
+ else
+ val1 = 200 + 200*skilllv;
+ if(src->x == x && src->y == y)
+ dir = 2;
+ else
+ dir=map_calc_dir(src,x,y);
+ ux+=(2-i)*diry[dir];
+ uy+=(i-2)*dirx[dir];
+ }
+ break;
+
+ case WZ_QUAGMIRE: /* クァグマイア */
+ ux+=(i%5-2);
+ uy+=(i/5-2);
+ if(i==12)
+ range=2;
+ else
+ range=-1;
+
+ break;
+
+ case AS_VENOMDUST: /* ベノムダスト */
+ {
+ static const int dx[]={-1,0,0,0,1};
+ static const int dy[]={0,-1,0,1,0};
+ ux+=dx[i];
+ uy+=dy[i];
+ }
+ break;
+
+ case CR_GRANDCROSS: /* グランドクロス */
+ {
+ static const int dx[]={
+ 0, 0, -1,0,1, -2,-1,0,1,2, -4,-3,-2,-1,0,1,2,3,4, -2,-1,0,1,2, -1,0,1, 0, 0, };
+ static const int dy[]={
+ -4, -3, -2,-2,-2, -1,-1,-1,-1,-1, 0,0,0,0,0,0,0,0,0, 1,1,1,1,1, 2,2,2, 3, 4, };
+ ux+=dx[i];
+ uy+=dy[i];
+ }
+ break;
+ case SA_VOLCANO: /* ボルケーノ */
+ case SA_DELUGE: /* デリュージ */
+ case SA_VIOLENTGALE: /* バイオレントゲイル */
+ {
+ int u_range=0,central=0;
+ if(skilllv<=2){
+ u_range=2;
+ central=12;
+ }else if(skilllv<=4){
+ u_range=3;
+ central=24;
+ }else if(skilllv>=5){
+ u_range=4;
+ central=40;
+ }
+ ux+=(i%(u_range*2+1)-u_range);
+ uy+=(i/(u_range*2+1)-u_range);
+
+ if(i==central)
+ range=u_range;//中央のユニットの効果範囲は全範囲
+ else
+ range=-1;//中央以外のユニットは飾り
+ }
+ break;
+ case SA_LANDPROTECTOR: /* ランドプロテクター */
+ {
+ int u_range=0;
+
+ if(skilllv<=2) u_range=3;
+ else if(skilllv<=4) u_range=4;
+ else if(skilllv>=5) u_range=5;
+
+ ux+=(i%(u_range*2+1)-u_range);
+ uy+=(i/(u_range*2+1)-u_range);
+
+ range=0;
+ }
+ break;
+
+ /* ダンスなど */
+ case BD_LULLABY: /* 子守歌 */
+ case BD_RICHMANKIM: /* ニヨルドの宴 */
+ case BD_ETERNALCHAOS: /* 永遠の混沌 */
+ case BD_DRUMBATTLEFIELD:/* 戦太鼓の響き */
+ case BD_RINGNIBELUNGEN: /* ニーベルングの指輪 */
+ case BD_ROKISWEIL: /* ロキの叫び */
+ case BD_INTOABYSS: /* 深淵の中に */
+ case BD_SIEGFRIED: /* 不死身のジークフリード */
+ ux+=(i%9-4);
+ uy+=(i/9-4);
+ if(i==40)
+ range=4; /* 中心の場合は範囲を4にオーバーライド */
+ else
+ range=-1; /* 中心じゃない場合は範囲を-1にオーバーライド */
+ break;
+ case BA_DISSONANCE: /* 不協和音 */
+ case BA_WHISTLE: /* 口笛 */
+ case BA_ASSASSINCROSS: /* 夕陽のアサシンクロス */
+ case BA_POEMBRAGI: /* ブラギの詩 */
+ case BA_APPLEIDUN: /* イドゥンの林檎 */
+ case DC_UGLYDANCE: /* 自分勝手なダンス */
+ case DC_HUMMING: /* ハミング */
+ case DC_DONTFORGETME: /* 私を忘れないで… */
+ case DC_FORTUNEKISS: /* 幸運のキス */
+ case DC_SERVICEFORYOU: /* サービスフォーユー */
+ ux+=(i%7-3);
+ uy+=(i/7-3);
+ if(i==40)
+ range=4; /* 中心の場合は範囲を4にオーバーライド */
+ else
+ range=-1; /* 中心じゃない場合は範囲を-1にオーバーライド */
+ break;
+ case PA_GOSPEL: /* ゴスペル */
+ ux+=(i%7-3);
+ uy+=(i/7-3);
+ break;
+ case PF_FOGWALL: /* フォグウォール */
+ ux+=(i%5-2);
+ uy+=(i/5-1);
+ break;
+ case RG_GRAFFITI: /* Graffiti [Valaris] */
+ ux+=(i%5-2);
+ uy+=(i/5-2);
+ break;
+ }
+ //直上スキルの場合設置座標上にランドプロテクターがないかチェック
+ if(range<=0)
+ map_foreachinarea(skill_landprotector,src->m,ux,uy,ux,uy,BL_SKILL,skillid,&alive);
+
+ if(skillid==WZ_ICEWALL && alive){
+ val2=map_getcell(src->m,ux,uy);
+ if(val2==5 || val2==1)
+ alive=0;
+ else {
+ map_setcell(src->m,ux,uy,5);
+ clif_changemapcell(src->m,ux,uy,5,0);
+ }
+ }
+
+ if(alive){
+ nullpo_retr(NULL, unit=skill_initunit(group,i,ux,uy));
+ unit->val1=val1;
+ unit->val2=val2;
+ unit->limit=limit;
+ unit->range=range;
+ }
+ }
+ return group;
+}
+
+/*==========================================
+ * スキルユニットの発動イベント
+ *------------------------------------------
+ */
+int skill_unit_onplace(struct skill_unit *src,struct block_list *bl,unsigned int tick)
+{
+ struct skill_unit_group *sg;
+ struct block_list *ss;
+ struct skill_unit_group_tickset *ts;
+ struct map_session_data *srcsd=NULL;
+ int diff,goflag,splash_count=0;
+
+ nullpo_retr(0, src);
+ nullpo_retr(0, bl);
+
+ if( bl->prev==NULL || !src->alive || (bl->type == BL_PC && pc_isdead((struct map_session_data *)bl) ) )
+ return 0;
+
+ nullpo_retr(0, sg=src->group);
+ nullpo_retr(0, ss=map_id2bl(sg->src_id));
+
+ if(ss->type == BL_PC)
+ nullpo_retr(0, srcsd=(struct map_session_data *)ss);
+ if(srcsd && srcsd->chatID)
+ return 0;
+
+ if( bl->type!=BL_PC && bl->type!=BL_MOB )
+ return 0;
+ nullpo_retr(0, ts=skill_unitgrouptickset_search( bl, sg->group_id));
+ diff=DIFF_TICK(tick,ts->tick);
+ goflag=(diff>sg->interval || diff<0);
+ if (sg->skill_id == CR_GRANDCROSS && !battle_config.gx_allhit) // 重なっていたら3HITしない
+ goflag = (diff>sg->interval*map_count_oncell(bl->m,bl->x,bl->y) || diff<0);
+
+ //対象がLP上に居る場合は無効
+ map_foreachinarea(skill_landprotector,bl->m,bl->x,bl->y,bl->x,bl->y,BL_SKILL,0,&goflag);
+
+ if(!goflag)
+ return 0;
+ ts->tick=tick;
+ ts->group_id=sg->group_id;
+
+ switch(sg->unit_id){
+ case 0x83: /* サンクチュアリ */
+ {
+ int race=battle_get_race(bl);
+ int damage_flag = (battle_check_undead(race,battle_get_elem_type(bl)) || race == 6)? 1:0;
+
+ if( battle_get_hp(bl)>=battle_get_max_hp(bl) && !damage_flag)
+ break;
+
+ if((sg->val1--)<=0){
+ skill_delunitgroup(sg);
+ return 0;
+ }
+ if(!damage_flag) {
+ int heal=sg->val2;
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage)
+ heal=0; /* 黄金蟲カード(ヒール量0) */
+ clif_skill_nodamage(&src->bl,bl,AL_HEAL,heal,1);
+ battle_heal(NULL,bl,heal,0,0);
+ }
+ else
+ skill_attack(BF_MAGIC,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0);
+ }
+ break;
+
+ case 0x84: /* マグヌスエクソシズム */
+ {
+ int race=battle_get_race(bl);
+ int damage_flag = (battle_check_undead(race,battle_get_elem_type(bl)) || race == 6)? 1:0;
+
+ if(!damage_flag)
+ return 0;
+ skill_attack(BF_MAGIC,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0);
+ }
+ break;
+
+ case 0x85: /* ニューマ */
+ {
+ struct skill_unit *unit2;
+ struct status_change *sc_data=battle_get_sc_data(bl);
+ int type=SC_PNEUMA;
+ if(sc_data && sc_data[type].timer==-1)
+ skill_status_change_start(bl,type,sg->skill_lv,(int)src,0,0,0,0);
+ else if((unit2=(struct skill_unit *)sc_data[type].val2) && unit2 != src ){
+ if(DIFF_TICK(sg->tick,unit2->group->tick)>0 )
+ skill_status_change_start(bl,type,sg->skill_lv,(int)src,0,0,0,0);
+ ts->tick-=sg->interval;
+ }
+ }
+ break;
+ case 0x7e: /* セイフティウォール */
+ {
+ struct skill_unit *unit2;
+ struct status_change *sc_data=battle_get_sc_data(bl);
+ int type=SC_SAFETYWALL;
+ if(sc_data && sc_data[type].timer==-1)
+ skill_status_change_start(bl,type,sg->skill_lv,(int)src,0,0,0,0);
+ else if((unit2=(struct skill_unit *)sc_data[type].val2) && unit2 != src ){
+ if(sg->val1 < unit2->group->val1 )
+ skill_status_change_start(bl,type,sg->skill_lv,(int)src,0,0,0,0);
+ ts->tick-=sg->interval;
+ }
+ }
+ break;
+
+ case 0x86: /* ロードオブヴァーミリオン(&ストームガスト &グランドクロス) */
+ skill_attack(BF_MAGIC,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0);
+ break;
+
+ case 0x7f: /* ファイヤーウォール */
+ if( (src->val2--)>0)
+ skill_attack(BF_MAGIC,ss,&src->bl,bl,
+ sg->skill_id,sg->skill_lv,tick,0);
+ if( src->val2<=0 )
+ skill_delunit(src);
+ break;
+
+ case 0x87: /* ファイアーピラー(発動前) */
+ skill_delunit(src);
+ skill_unitsetting(ss,sg->skill_id,sg->skill_lv,src->bl.x,src->bl.y,1);
+ break;
+
+ case 0x88: /* ファイアーピラー(発動後) */
+ if(DIFF_TICK(tick,sg->tick) < 150)
+ skill_attack(BF_MAGIC,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0);
+ break;
+
+ case 0x90: /* スキッドトラップ */
+ {
+ int i,c = skill_get_blewcount(sg->skill_id,sg->skill_lv);
+ if(map[bl->m].flag.gvg) c = 0;
+ for(i=0;i<c;i++)
+ skill_blown(&src->bl,bl,1|0x30000);
+ sg->unit_id = 0x8c;
+ clif_changelook(&src->bl,LOOK_BASE,sg->unit_id);
+ sg->limit=DIFF_TICK(tick,sg->tick)+1500;
+ }
+ break;
+
+ case 0x93: /* ランドマイン */
+ skill_attack(BF_MISC,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0);
+ sg->unit_id = 0x8c;
+ clif_changelook(&src->bl,LOOK_BASE,0x88);
+ sg->limit=DIFF_TICK(tick,sg->tick)+1500;
+ break;
+
+ case 0x8f: /* ブラストマイン */
+ case 0x94: /* ショックウェーブトラップ */
+ case 0x95: /* サンドマン */
+ case 0x96: /* フラッシャー */
+ case 0x97: /* フリージングトラップ */
+ case 0x98: /* クレイモアートラップ */
+ map_foreachinarea(skill_count_target,src->bl.m
+ ,src->bl.x-src->range,src->bl.y-src->range
+ ,src->bl.x+src->range,src->bl.y+src->range
+ ,0,&src->bl,&splash_count);
+ map_foreachinarea(skill_trap_splash,src->bl.m
+ ,src->bl.x-src->range,src->bl.y-src->range
+ ,src->bl.x+src->range,src->bl.y+src->range
+ ,0,&src->bl,tick,splash_count);
+ sg->unit_id = 0x8c;
+ clif_changelook(&src->bl,LOOK_BASE,sg->unit_id);
+ sg->limit=DIFF_TICK(tick,sg->tick)+1500;
+ break;
+
+ case 0x91: /* アンクルスネア */
+ {
+ struct status_change *sc_data=battle_get_sc_data(bl);
+ if(sg->val2==0 && sc_data && sc_data[SC_ANKLE].timer==-1){
+ int moveblock = ( bl->x/BLOCK_SIZE != src->bl.x/BLOCK_SIZE || bl->y/BLOCK_SIZE != src->bl.y/BLOCK_SIZE);
+ int sec=skill_get_time2(sg->skill_id,sg->skill_lv) - (double)battle_get_agi(bl)*0.1;
+ if(battle_get_mode(bl)&0x20)
+ sec = sec/5;
+ battle_stopwalking(bl,1);
+ skill_status_change_start(bl,SC_ANKLE,sg->skill_lv,0,0,0,sec,0);
+
+ if(moveblock) map_delblock(bl);
+ bl->x = src->bl.x;
+ bl->y = src->bl.y;
+ if(moveblock) map_addblock(bl);
+ if(bl->type == BL_MOB)
+ clif_fixmobpos((struct mob_data *)bl);
+ else if(bl->type == BL_PET)
+ clif_fixpetpos((struct pet_data *)bl);
+ else
+ clif_fixpos(bl);
+ clif_01ac(&src->bl);
+ sg->limit=DIFF_TICK(tick,sg->tick) + sec;
+ sg->val2=bl->id;
+ }
+ }
+ break;
+
+ case 0x80: /* ワープポータル(発動後) */
+ if(bl->type==BL_PC){
+ struct map_session_data *sd = (struct map_session_data *)bl;
+ if(sd && src->bl.m == bl->m && src->bl.x == bl->x && src->bl.y == bl->y && src->bl.x == sd->to_x && src->bl.y == sd->to_y) {
+ if( battle_config.chat_warpportal || !sd->chatID ){
+ if((sg->val1--)>0){
+ pc_setpos(sd,sg->valstr,sg->val2>>16,sg->val2&0xffff,3);
+ if(sg->src_id == bl->id ||( strcmp(map[src->bl.m].name,sg->valstr) == 0 && src->bl.x == (sg->val2>>16) && src->bl.y == (sg->val2&0xffff) ))
+ skill_delunitgroup(sg);
+ }else
+ skill_delunitgroup(sg);
+ }
+ }
+ }else if(bl->type==BL_MOB && battle_config.mob_warpportal){
+ int m=map_mapname2mapid(sg->valstr);
+ struct mob_data *md;
+ md=(struct mob_data *)bl;
+ mob_warp((struct mob_data *)bl,m,sg->val2>>16,sg->val2&0xffff,3);
+ }
+ break;
+
+ case 0x8e: /* クァグマイア */
+ {
+ int type=SkillStatusChangeTable[sg->skill_id];
+ if( bl->type==BL_PC && ((struct map_session_data *)bl)->special_state.no_magic_damage )
+ break;
+ if( battle_get_sc_data(bl)[type].timer==-1 )
+ skill_status_change_start(bl,type,sg->skill_lv,(int)src,0,0,skill_get_time2(sg->skill_id,sg->skill_lv),0);
+ }
+ break;
+ case 0x92: /* ベノムダスト */
+ {
+ struct status_change *sc_data=battle_get_sc_data(bl);
+ int type=SkillStatusChangeTable[sg->skill_id];
+ if( sc_data && sc_data[type].timer==-1 )
+ skill_status_change_start(bl,type,sg->skill_lv,(int)src,0,0,skill_get_time2(sg->skill_id,sg->skill_lv),0);
+ }
+ break;
+ case 0x9a: /* ボルケーノ */
+ case 0x9b: /* デリュージ */
+ case 0x9c: /* バイオレントゲイル */
+ {
+ struct skill_unit *unit2;
+ struct status_change *sc_data=battle_get_sc_data(bl);
+ int type=SkillStatusChangeTable[sg->skill_id];
+ if(sc_data && sc_data[type].timer==-1)
+ skill_status_change_start(bl,type,sg->skill_lv,(int)src,0,0,skill_get_time2(sg->skill_id,sg->skill_lv),0);
+ else if((unit2=(struct skill_unit *)sc_data[type].val2) && unit2 != src ){
+ if( DIFF_TICK(sg->tick,unit2->group->tick)>0 )
+ skill_status_change_start(bl,type,sg->skill_lv,(int)src,0,0,skill_get_time2(sg->skill_id,sg->skill_lv),0);
+ ts->tick-=sg->interval;
+ }
+ } break;
+
+ case 0x9e: /* 子守唄 */
+ case 0x9f: /* ニヨルドの宴 */
+ case 0xa0: /* 永遠の混沌 */
+ case 0xa1: /* 戦太鼓の響き */
+ case 0xa2: /* ニーベルングの指輪 */
+ case 0xa3: /* ロキの叫び */
+ case 0xa4: /* 深淵の中に */
+ case 0xa5: /* 不死身のジークフリード */
+ case 0xa6: /* 不協和音 */
+ case 0xa7: /* 口笛 */
+ case 0xa8: /* 夕陽のアサシンクロス */
+ case 0xa9: /* ブラギの詩 */
+ case 0xab: /* 自分勝手なダンス */
+ case 0xac: /* ハミング */
+ case 0xad: /* 私を忘れないで… */
+ case 0xae: /* 幸運のキス */
+ case 0xaf: /* サービスフォーユー */
+ case 0xb4:
+ {
+ struct skill_unit *unit2;
+ struct status_change *sc_data=battle_get_sc_data(bl);
+ int type=SkillStatusChangeTable[sg->skill_id];
+ if(sg->src_id == bl->id)
+ break;
+ if(sc_data && sc_data[type].timer==-1)
+ skill_status_change_start(bl,type,sg->skill_lv,sg->val1,sg->val2,
+ (int)src,skill_get_time2(sg->skill_id,sg->skill_lv),0);
+ else if( (unit2=(struct skill_unit *)sc_data[type].val4) && unit2 != src ){
+ if( unit2->group && DIFF_TICK(sg->tick,unit2->group->tick)>0 )
+ skill_status_change_start(bl,type,sg->skill_lv,sg->val1,sg->val2,
+ (int)src,skill_get_time2(sg->skill_id,sg->skill_lv),0);
+ ts->tick-=sg->interval;
+ }
+ } break;
+
+ case 0xaa: /* イドゥンの林檎 */
+ {
+ struct skill_unit *unit2;
+ struct status_change *sc_data=battle_get_sc_data(bl);
+ int type=SkillStatusChangeTable[sg->skill_id];
+ if(sg->src_id == bl->id)
+ break;
+ if( sc_data && sc_data[type].timer==-1)
+ skill_status_change_start(bl,type,sg->skill_lv,(sg->val1)>>16,(sg->val1)&0xffff,
+ (int)src,skill_get_time2(sg->skill_id,sg->skill_lv),0);
+ else if((unit2=(struct skill_unit *)sc_data[type].val4) && unit2 != src ){
+ if( DIFF_TICK(sg->tick,unit2->group->tick)>0 )
+ skill_status_change_start(bl,type,sg->skill_lv,(sg->val1)>>16,(sg->val1)&0xffff,
+ (int)src,skill_get_time2(sg->skill_id,sg->skill_lv),0);
+ ts->tick-=sg->interval;
+ }
+ } break;
+
+ case 0xb1: /* デモンストレーション */
+ skill_attack(BF_WEAPON,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0);
+ if(bl->type == BL_PC && rand()%100 < sg->skill_lv && battle_config.equipment_breaking)
+ pc_breakweapon((struct map_session_data *)bl);
+ break;
+ case 0x99: /* トーキーボックス */
+ if(sg->src_id == bl->id) //自分が踏んでも発動しない
+ break;
+ if(sg->val2==0){
+ clif_talkiebox(&src->bl,sg->valstr);
+ sg->unit_id = 0x8c;
+ clif_changelook(&src->bl,LOOK_BASE,sg->unit_id);
+ sg->limit=DIFF_TICK(tick,sg->tick)+5000;
+ sg->val2=-1; //踏んだ
+ }
+ break;
+ case 0xb2: /* あなたを_会いたいです */
+ case 0xb3: /* ゴスペル */
+ case 0xb6: /* フォグウォール */
+ //とりあえず何もしない
+ break;
+
+
+
+
+
+
+ case 0xb7: /* スパイダーウェッブ */
+ if(sg->val2==0){
+ int moveblock = ( bl->x/BLOCK_SIZE != src->bl.x/BLOCK_SIZE || bl->y/BLOCK_SIZE != src->bl.y/BLOCK_SIZE);
+ skill_additional_effect(ss,bl,sg->skill_id,sg->skill_lv,BF_MISC,tick);
+ if(moveblock) map_delblock(bl);
+ bl->x = (&src->bl)->x;
+ bl->y = (&src->bl)->y;
+ if(moveblock) map_addblock(bl);
+ if(bl->type == BL_MOB)
+ clif_fixmobpos((struct mob_data *)bl);
+ else if(bl->type == BL_PET)
+ clif_fixpetpos((struct pet_data *)bl);
+ else
+ clif_fixpos(bl);
+ clif_01ac(&src->bl);
+ sg->limit=DIFF_TICK(tick,sg->tick) + skill_get_time2(sg->skill_id,sg->skill_lv);
+ sg->val2=bl->id;
+ }
+ break;
+
+/* default:
+ if(battle_config.error_log)
+ printf("skill_unit_onplace: Unknown skill unit id=%d block=%d\n",sg->unit_id,bl->id);
+ break;*/
+ }
+ if(bl->type==BL_MOB && ss!=bl) /* スキル使用条件のMOBスキル */
+ {
+ if(battle_config.mob_changetarget_byskill == 1)
+ {
+ int target=((struct mob_data *)bl)->target_id;
+ if(ss->type == BL_PC)
+ ((struct mob_data *)bl)->target_id=ss->id;
+ mobskill_use((struct mob_data *)bl,tick,MSC_SKILLUSED|(sg->skill_id<<16));
+ ((struct mob_data *)bl)->target_id=target;
+ }
+ else
+ mobskill_use((struct mob_data *)bl,tick,MSC_SKILLUSED|(sg->skill_id<<16));
+ }
+
+ return 0;
+}
+/*==========================================
+ * スキルユニットから離脱する(もしくはしている)場合
+ *------------------------------------------
+ */
+int skill_unit_onout(struct skill_unit *src,struct block_list *bl,unsigned int tick)
+{
+ struct skill_unit_group *sg;
+
+ nullpo_retr(0, src);
+ nullpo_retr(0, bl);
+ nullpo_retr(0, sg=src->group);
+
+ if( bl->prev==NULL || !src->alive )
+ return 0;
+
+ if( bl->type!=BL_PC && bl->type!=BL_MOB )
+ return 0;
+
+ switch(sg->unit_id){
+ case 0x7e: /* セイフティウォール */
+ case 0x85: /* ニューマ */
+ case 0x8e: /* クァグマイア */
+ {
+ struct status_change *sc_data=battle_get_sc_data(bl);
+ int type=
+ (sg->unit_id==0x85)?SC_PNEUMA:
+ ((sg->unit_id==0x7e)?SC_SAFETYWALL:
+ SC_QUAGMIRE);
+ if((type != SC_QUAGMIRE || bl->type != BL_MOB) &&
+ sc_data && sc_data[type].timer!=-1 && ((struct skill_unit *)sc_data[type].val2)==src){
+ skill_status_change_end(bl,type,-1);
+ }
+ } break;
+
+ case 0x91: /* アンクルスネア */
+ {
+ struct block_list *target=map_id2bl(sg->val2);
+ if( target && target==bl ){
+ skill_status_change_end(bl,SC_ANKLE,-1);
+ sg->limit=DIFF_TICK(tick,sg->tick)+1000;
+ }
+ }
+ break;
+ case 0xb5:
+ case 0xb8:
+ {
+ struct block_list *target=map_id2bl(sg->val2);
+ if( target==bl )
+ skill_status_change_end(bl,SC_SPIDERWEB,-1);
+ sg->limit=DIFF_TICK(tick,sg->tick)+1000;
+ }
+ break;
+ case 0xb6:
+ {
+ struct block_list *target=map_id2bl(sg->val2);
+ if( target==bl )
+ skill_status_change_end(bl,SC_FOGWALL,-1);
+ sg->limit=DIFF_TICK(tick,sg->tick)+1000;
+ }
+ break;
+ case 0x9a: /* ボルケーノ */
+ case 0x9b: /* デリュージ */
+ case 0x9c: /* バイオレントゲイル */
+ {
+ struct status_change *sc_data=battle_get_sc_data(bl);
+ struct skill_unit *su;
+ int type=SkillStatusChangeTable[sg->skill_id];
+ if( sc_data && sc_data[type].timer!=-1 && (su=((struct skill_unit *)sc_data[type].val2)) && su == src ){
+ skill_status_change_end(bl,type,-1);
+ }
+ }
+ break;
+
+ case 0x9e: /* 子守唄 */
+ case 0x9f: /* ニヨルドの宴 */
+ case 0xa0: /* 永遠の混沌 */
+ case 0xa1: /* 戦太鼓の響き */
+ case 0xa2: /* ニーベルングの指輪 */
+ case 0xa3: /* ロキの叫び */
+ case 0xa4: /* 深淵の中に */
+ case 0xa5: /* 不死身のジークフリード */
+ case 0xa6: /* 不協和音 */
+ case 0xa7: /* 口笛 */
+ case 0xa8: /* 夕陽のアサシンクロス */
+ case 0xa9: /* ブラギの詩 */
+ case 0xaa: /* イドゥンの林檎 */
+ case 0xab: /* 自分勝手なダンス */
+ case 0xac: /* ハミング */
+ case 0xad: /* 私を忘れないで… */
+ case 0xae: /* 幸運のキス */
+ case 0xaf: /* サービスフォーユー */
+ case 0xb4:
+ {
+ struct status_change *sc_data=battle_get_sc_data(bl);
+ struct skill_unit *su;
+ int type=SkillStatusChangeTable[sg->skill_id];
+ if( sc_data && sc_data[type].timer!=-1 && (su=((struct skill_unit *)sc_data[type].val4)) && su == src ){
+ skill_status_change_end(bl,type,-1);
+ }
+ }
+ break;
+ case 0xb7: /* スパイダーウェッブ */
+ {
+ struct block_list *target=map_id2bl(sg->val2);
+ if( target && target==bl )
+ skill_status_change_end(bl,SC_SPIDERWEB,-1);
+ sg->limit=DIFF_TICK(tick,sg->tick)+1000;
+ }
+ break;
+
+/* default:
+ if(battle_config.error_log)
+ printf("skill_unit_onout: Unknown skill unit id=%d block=%d\n",sg->unit_id,bl->id);
+ break;*/
+ }
+ skill_unitgrouptickset_delete(bl,sg->group_id);
+ return 0;
+}
+/*==========================================
+ * スキルユニットの削除イベント
+ *------------------------------------------
+ */
+int skill_unit_ondelete(struct skill_unit *src,struct block_list *bl,unsigned int tick)
+{
+ struct skill_unit_group *sg;
+
+ nullpo_retr(0, src);
+ nullpo_retr(0, bl);
+ nullpo_retr(0, sg = src->group);
+
+ if( bl->prev==NULL || !src->alive )
+ return 0;
+
+ if( bl->type!=BL_PC && bl->type!=BL_MOB )
+ return 0;
+
+ switch(sg->unit_id){
+ case 0x85: /* ニューマ */
+ case 0x7e: /* セイフティウォール */
+ case 0x8e: /* クァグマイヤ */
+ case 0x9a: /* ボルケーノ */
+ case 0x9b: /* デリュージ */
+ case 0x9c: /* バイオレントゲイル */
+ case 0x9e: /* 子守唄 */
+ case 0x9f: /* ニヨルドの宴 */
+ case 0xa0: /* 永遠の混沌 */
+ case 0xa1: /* 戦太鼓の響き */
+ case 0xa2: /* ニーベルングの指輪 */
+ case 0xa3: /* ロキの叫び */
+ case 0xa4: /* 深淵の中に */
+ case 0xa5: /* 不死身のジークフリード */
+ case 0xa6: /* 不協和音 */
+ case 0xa7: /* 口笛 */
+ case 0xa8: /* 夕陽のアサシンクロス */
+ case 0xa9: /* ブラギの詩 */
+ case 0xaa: /* イドゥンの林檎 */
+ case 0xab: /* 自分勝手なダンス */
+ case 0xac: /* ハミング */
+ case 0xad: /* 私を忘れないで… */
+ case 0xae: /* 幸運のキス */
+ case 0xaf: /* サービスフォーユー */
+ case 0xb4:
+ return skill_unit_onout(src,bl,tick);
+
+/* default:
+ if(battle_config.error_log)
+ printf("skill_unit_ondelete: Unknown skill unit id=%d block=%d\n",sg->unit_id,bl->id);
+ break;*/
+ }
+ skill_unitgrouptickset_delete(bl,sg->group_id);
+ return 0;
+}
+/*==========================================
+ * スキルユニットの限界イベント
+ *------------------------------------------
+ */
+int skill_unit_onlimit(struct skill_unit *src,unsigned int tick)
+{
+ struct skill_unit_group *sg;
+
+ nullpo_retr(0, src);
+ nullpo_retr(0, sg=src->group);
+
+ switch(sg->unit_id){
+ case 0x81: /* ワープポータル(発動前) */
+ {
+ struct skill_unit_group *group=
+ skill_unitsetting(map_id2bl(sg->src_id),sg->skill_id,sg->skill_lv,
+ src->bl.x,src->bl.y,1);
+ if(group == NULL)
+ return 0;
+ group->valstr=calloc(24, 1);
+ if(group->valstr==NULL){
+ printf("skill_unit_onlimit: out of memory !\n");
+ exit(1);
+ }
+ memcpy(group->valstr,sg->valstr,24);
+ group->val2=sg->val2;
+ }
+ break;
+
+ case 0x8d: /* アイスウォール */
+ map_setcell(src->bl.m,src->bl.x,src->bl.y,src->val2);
+ clif_changemapcell(src->bl.m,src->bl.x,src->bl.y,src->val2,1);
+ break;
+ case 0xb2: /* あなたに会いたい */
+ {
+ struct map_session_data *sd = NULL;
+ struct map_session_data *p_sd = NULL;
+ if((sd = (struct map_session_data *)(map_id2bl(sg->src_id))) == NULL)
+ return 0;
+ if((p_sd = pc_get_partner(sd)) == NULL)
+ return 0;
+
+ pc_setpos(p_sd,map[src->bl.m].name,src->bl.x,src->bl.y,3);
+ }
+ break;
+ }
+ return 0;
+}
+/*==========================================
+ * スキルユニットのダメージイベント
+ *------------------------------------------
+ */
+int skill_unit_ondamaged(struct skill_unit *src,struct block_list *bl,
+ int damage,unsigned int tick)
+{
+ struct skill_unit_group *sg;
+
+ nullpo_retr(0, src);
+ nullpo_retr(0, sg=src->group);
+
+ switch(sg->unit_id){
+ case 0x8d: /* アイスウォール */
+ src->val1-=damage;
+ break;
+ case 0x8f: /* ブラストマイン */
+ case 0x98: /* クレイモアートラップ */
+ skill_blown(bl,&src->bl,2); //吹き飛ばしてみる
+ break;
+ default:
+ damage = 0;
+ break;
+ }
+ return damage;
+}
+
+
+/*---------------------------------------------------------------------------- */
+
+/*==========================================
+ * スキル使用(詠唱完了、場所指定)
+ *------------------------------------------
+ */
+int skill_castend_pos( int tid, unsigned int tick, int id,int data )
+{
+ struct map_session_data* sd=map_id2sd(id)/*,*target_sd=NULL*/;
+ int range,maxcount;
+
+ nullpo_retr(0, sd);
+
+ if( sd->bl.prev == NULL )
+ return 0;
+ if( sd->skilltimer != tid ) /* タイマIDの確認 */
+ return 0;
+ if(sd->skilltimer != -1 && pc_checkskill(sd,SA_FREECAST) > 0) {
+ sd->speed = sd->prev_speed;
+ clif_updatestatus(sd,SP_SPEED);
+ }
+ sd->skilltimer=-1;
+ if(pc_isdead(sd)) {
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+
+ if(battle_config.pc_skill_reiteration == 0) {
+ range = -1;
+ switch(sd->skillid) {
+ case MG_SAFETYWALL:
+ case WZ_FIREPILLAR:
+ case HT_SKIDTRAP:
+ case HT_LANDMINE:
+ case HT_ANKLESNARE:
+ case HT_SHOCKWAVE:
+ case HT_SANDMAN:
+ case HT_FLASHER:
+ case HT_FREEZINGTRAP:
+ case HT_BLASTMINE:
+ case HT_CLAYMORETRAP:
+ case HT_TALKIEBOX:
+ case AL_WARP:
+ case PF_SPIDERWEB: /* スパイダーウェッブ */
+ case RG_GRAFFITI: /* グラフィティ */
+ range = 0;
+ break;
+ case AL_PNEUMA:
+ range = 1;
+ break;
+ }
+ if(range >= 0) {
+ if(skill_check_unit_range(sd->bl.m,sd->skillx,sd->skilly,range,sd->skillid) > 0) {
+ clif_skill_fail(sd,sd->skillid,0,0);
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+ }
+ }
+ if(battle_config.pc_skill_nofootset) {
+ range = -1;
+ switch(sd->skillid) {
+ case WZ_FIREPILLAR:
+ case HT_SKIDTRAP:
+ case HT_LANDMINE:
+ case HT_ANKLESNARE:
+ case HT_SHOCKWAVE:
+ case HT_SANDMAN:
+ case HT_FLASHER:
+ case HT_FREEZINGTRAP:
+ case HT_BLASTMINE:
+ case HT_CLAYMORETRAP:
+ case HT_TALKIEBOX:
+ case PF_SPIDERWEB: /* スパイダーウェッブ */
+ case WZ_ICEWALL:
+ range = 1;
+ break;
+ case AL_WARP:
+ range = 0;
+ break;
+ }
+ if(range >= 0) {
+ if(skill_check_unit_range2(sd->bl.m,sd->skillx,sd->skilly,range) > 0) {
+ clif_skill_fail(sd,sd->skillid,0,0);
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+ }
+ }
+
+ if(battle_config.pc_land_skill_limit) {
+ maxcount = skill_get_maxcount(sd->skillid);
+ if(maxcount > 0) {
+ int i,c;
+ for(i=c=0;i<MAX_SKILLUNITGROUP;i++) {
+ if(sd->skillunit[i].alive_count > 0 && sd->skillunit[i].skill_id == sd->skillid)
+ c++;
+ }
+ if(c >= maxcount) {
+ clif_skill_fail(sd,sd->skillid,0,0);
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+ }
+ }
+
+ range = skill_get_range(sd->skillid,sd->skilllv);
+ if(range < 0)
+ range = battle_get_range(&sd->bl) - (range + 1);
+ range += battle_config.pc_skill_add_range;
+ if(battle_config.skill_out_range_consume) { // changed to allow casting when target walks out of range [Valaris]
+ if(range < distance(sd->bl.x,sd->bl.y,sd->skillx,sd->skilly)) {
+ clif_skill_fail(sd,sd->skillid,0,0);
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+ }
+ if(!skill_check_condition(sd,1)) { /* 使用条件チェック */
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+ sd->skillitem = sd->skillitemlv = -1;
+ if(battle_config.skill_out_range_consume) {
+ if(range < distance(sd->bl.x,sd->bl.y,sd->skillx,sd->skilly)) {
+ clif_skill_fail(sd,sd->skillid,0,0);
+ sd->canact_tick = tick;
+ sd->canmove_tick = tick;
+ return 0;
+ }
+ }
+
+ if(battle_config.pc_skill_log)
+ printf("PC %d skill castend skill=%d\n",sd->bl.id,sd->skillid);
+ pc_stop_walking(sd,0);
+
+ skill_castend_pos2(&sd->bl,sd->skillx,sd->skilly,sd->skillid,sd->skilllv,tick,0);
+
+ return 0;
+}
+
+/*==========================================
+ * 範囲内キャラ存在確認判定処理(foreachinarea)
+ *------------------------------------------
+ */
+
+static int skill_check_condition_char_sub(struct block_list *bl,va_list ap)
+{
+ int *c;
+ struct block_list *src;
+ struct map_session_data *sd;
+ struct map_session_data *ssd;
+ struct pc_base_job s_class;
+ struct pc_base_job ss_class;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, sd=(struct map_session_data*)bl);
+ nullpo_retr(0, src=va_arg(ap,struct block_list *));
+ nullpo_retr(0, c=va_arg(ap,int *));
+ nullpo_retr(0, ssd=(struct map_session_data*)src);
+
+ s_class = pc_calc_base_job(sd->status.class);
+ //チェックしない設定ならcにありえない大きな数字を返して終了
+ if(!battle_config.player_skill_partner_check){ //本当はforeachの前にやりたいけど設定適用箇所をまとめるためにここへ
+ (*c)=99;
+ return 0;
+ }
+
+ ;
+ ss_class = pc_calc_base_job(ssd->status.class);
+
+ switch(ssd->skillid){
+ case PR_BENEDICTIO: /* 聖体降福 */
+ if(sd != ssd && (sd->status.class == 4 || sd->status.class == 8 || sd->status.class == 15 ||
+ sd->status.class == 4005 || sd->status.class == 4009 || sd->status.class == 4016) &&
+ (sd->bl.x == ssd->bl.x - 1 || sd->bl.x == ssd->bl.x + 1) && sd->status.sp >= 10)
+ (*c)++;
+ break;
+ case BD_LULLABY: /* 子守歌 */
+ case BD_RICHMANKIM: /* ニヨルドの宴 */
+ case BD_ETERNALCHAOS: /* 永遠の混沌 */
+ case BD_DRUMBATTLEFIELD: /* 戦太鼓の響き */
+ case BD_RINGNIBELUNGEN: /* ニーベルングの指輪 */
+ case BD_ROKISWEIL: /* ロキの叫び */
+ case BD_INTOABYSS: /* 深淵の中に */
+ case BD_SIEGFRIED: /* 不死身のジークフリード */
+ case BD_RAGNAROK: /* 神々の黄昏 */
+ case CG_MOONLIT: /* 月明りの泉に落ちる花びら */
+ if(sd != ssd &&
+ ((ssd->status.class==19 && sd->status.class==20) ||
+ (ssd->status.class==20 && sd->status.class==19) ||
+ (ssd->status.class==4020 && sd->status.class==4021) ||
+ (ssd->status.class==4021 && sd->status.class==4020) ||
+ (ssd->status.class==20 && sd->status.class==4020) ||
+ (ssd->status.class==19 && sd->status.class==4021)) &&
+ pc_checkskill(sd,ssd->skillid) > 0 &&
+ (*c)==0 &&
+ sd->status.party_id == ssd->status.party_id &&
+ !pc_issit(sd) &&
+ sd->sc_data[SC_DANCING].timer==-1
+ )
+ (*c)=pc_checkskill(sd,ssd->skillid);
+ break;
+ }
+ return 0;
+}
+/*==========================================
+ * 範囲内キャラ存在確認判定後スキル使用処理(foreachinarea)
+ *------------------------------------------
+ */
+
+static int skill_check_condition_use_sub(struct block_list *bl,va_list ap)
+{
+ int *c;
+ struct block_list *src;
+ struct map_session_data *sd;
+ struct map_session_data *ssd;
+ struct pc_base_job s_class;
+ struct pc_base_job ss_class;
+ int skillid,skilllv;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, sd=(struct map_session_data*)bl);
+ nullpo_retr(0, src=va_arg(ap,struct block_list *));
+ nullpo_retr(0, c=va_arg(ap,int *));
+ nullpo_retr(0, ssd=(struct map_session_data*)src);
+
+ s_class = pc_calc_base_job(sd->status.class);
+
+ //チェックしない設定ならcにありえない大きな数字を返して終了
+ if(!battle_config.player_skill_partner_check){ //本当はforeachの前にやりたいけど設定適用箇所をまとめるためにここへ
+ (*c)=99;
+ return 0;
+ }
+
+ ss_class = pc_calc_base_job(ssd->status.class);
+ skillid=ssd->skillid;
+ skilllv=ssd->skilllv;
+ switch(skillid){
+ case PR_BENEDICTIO: /* 聖体降福 */
+ if(sd != ssd && (sd->status.class == 4 || sd->status.class == 8 || sd->status.class == 15 ||
+ sd->status.class == 4005 || sd->status.class == 4009 || sd->status.class == 4016) &&
+ (sd->bl.x == ssd->bl.x - 1 || sd->bl.x == ssd->bl.x + 1) && sd->status.sp >= 10){
+ sd->status.sp -= 10;
+ pc_calcstatus(sd,0);
+ (*c)++;
+ }
+ break;
+ case BD_LULLABY: /* 子守歌 */
+ case BD_RICHMANKIM: /* ニヨルドの宴 */
+ case BD_ETERNALCHAOS: /* 永遠の混沌 */
+ case BD_DRUMBATTLEFIELD: /* 戦太鼓の響き */
+ case BD_RINGNIBELUNGEN: /* ニーベルングの指輪 */
+ case BD_ROKISWEIL: /* ロキの叫び */
+ case BD_INTOABYSS: /* 深淵の中に */
+ case BD_SIEGFRIED: /* 不死身のジークフリード */
+ case BD_RAGNAROK: /* 神々の黄昏 */
+ case CG_MOONLIT: /* 月明りの泉に落ちる花びら */
+ if(sd != ssd && //本人以外で
+ ((ssd->status.class==19 && sd->status.class==20) ||
+ (ssd->status.class==20 && sd->status.class==19) ||
+ (ssd->status.class==4020 && sd->status.class==4021) ||
+ (ssd->status.class==4021 && sd->status.class==4020) ||
+ (ssd->status.class==20 && sd->status.class==4020) ||
+ (ssd->status.class==19 && sd->status.class==4021)) && //自分がダンサーならバードで
+ pc_checkskill(sd,skillid) > 0 && //スキルを持っていて
+ (*c)==0 && //最初の一人で
+ sd->status.party_id == ssd->status.party_id && //パーティーが同じで
+ !pc_issit(sd) && //座ってない
+ sd->sc_data[SC_DANCING].timer==-1 //ダンス中じゃない
+ ){
+ ssd->sc_data[SC_DANCING].val4=bl->id;
+ clif_skill_nodamage(bl,src,skillid,skilllv,1);
+ skill_status_change_start(bl,SC_DANCING,skillid,ssd->sc_data[SC_DANCING].val2,0,src->id,skill_get_time(skillid,skilllv)+1000,0);
+ sd->skillid_dance=sd->skillid=skillid;
+ sd->skilllv_dance=sd->skilllv=skilllv;
+ (*c)++;
+ }
+ break;
+ }
+ return 0;
+}
+/*==========================================
+ * 範囲内バイオプラント、スフィアマイン用Mob存在確認判定処理(foreachinarea)
+ *------------------------------------------
+ */
+
+static int skill_check_condition_mob_master_sub(struct block_list *bl,va_list ap)
+{
+ int *c,src_id=0,mob_class=0;
+ struct mob_data *md;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, md=(struct mob_data*)bl);
+ nullpo_retr(0, src_id=va_arg(ap,int));
+ nullpo_retr(0, mob_class=va_arg(ap,int));
+ nullpo_retr(0, c=va_arg(ap,int *));
+
+ if(md->class==mob_class && md->master_id==src_id)
+ (*c)++;
+ return 0;
+}
+
+/*==========================================
+ * スキル使用条件(偽で使用失敗)
+ *------------------------------------------
+ */
+int skill_check_condition(struct map_session_data *sd,int type)
+{
+ int i,hp,sp,hp_rate,sp_rate,zeny,weapon,state,spiritball,skill,lv,mhp;
+ int index[10],itemid[10],amount[10];
+
+ nullpo_retr(0, sd);
+
+ if( battle_config.gm_skilluncond>0 && pc_isGM(sd)>= battle_config.gm_skilluncond ) {
+ sd->skillitem = sd->skillitemlv = -1;
+ return 1;
+ }
+
+ if( sd->opt1>0) {
+ clif_skill_fail(sd,sd->skillid,0,0);
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+ if(pc_is90overweight(sd)) {
+ clif_skill_fail(sd,sd->skillid,9,0);
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+
+ if(sd->skillid == AC_MAKINGARROW && sd->state.make_arrow_flag == 1) {
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+ if(sd->skillid == AM_PHARMACY && sd->state.produce_flag == 1) {
+ sd->skillitem = sd->skillitemlv = -1;
+ return 0;
+ }
+
+ if(sd->skillitem == sd->skillid) { /* アイテムの場合無条件成功 */
+ if(type&1)
+ sd->skillitem = sd->skillitemlv = -1;
+ return 1;
+ }
+ if( sd->opt1>0 ){
+ clif_skill_fail(sd,sd->skillid,0,0);
+ return 0;
+ }
+ if(sd->sc_data){
+ if( sd->sc_data[SC_DIVINA].timer!=-1 ||
+ sd->sc_data[SC_ROKISWEIL].timer!=-1 ||
+ (sd->sc_data[SC_AUTOCOUNTER].timer != -1 && sd->skillid != KN_AUTOCOUNTER) ||
+ sd->sc_data[SC_STEELBODY].timer != -1 ||
+ sd->sc_data[SC_BERSERK].timer != -1
+ ){
+ clif_skill_fail(sd,sd->skillid,0,0);
+ return 0; /* 状態異常や沈黙など */
+ }
+ }
+ skill = sd->skillid;
+ lv = sd->skilllv;
+ hp=skill_get_hp(skill, lv); /* 消費HP */
+ sp=skill_get_sp(skill, lv); /* 消費SP */
+ if((sd->skillid_old == BD_ENCORE) && skill==sd->skillid_dance)
+ sp=sp/2; //アンコール時はSP消費が半分
+ hp_rate = (lv <= 0)? 0:skill_db[skill].hp_rate[lv-1];
+ sp_rate = (lv <= 0)? 0:skill_db[skill].sp_rate[lv-1];
+ zeny = skill_get_zeny(skill,lv);
+ weapon = skill_db[skill].weapon;
+ state = skill_db[skill].state;
+ spiritball = (lv <= 0)? 0:skill_db[skill].spiritball[lv-1];
+ mhp=skill_get_mhp(skill, lv); /* 消費HP */
+ for(i=0;i<10;i++) {
+ itemid[i] = skill_db[skill].itemid[i];
+ amount[i] = skill_db[skill].amount[i];
+ }
+ if(mhp > 0)
+ hp += (sd->status.max_hp * mhp)/100;
+ if(hp_rate > 0)
+ hp += (sd->status.hp * hp_rate)/100;
+ else
+ hp += (sd->status.max_hp * abs(hp_rate))/100;
+ if(sp_rate > 0)
+ sp += (sd->status.sp * sp_rate)/100;
+ else
+ sp += (sd->status.max_sp * abs(sp_rate))/100;
+ if(sd->dsprate!=100)
+ sp=sp*sd->dsprate/100; /* 消費SP修正 */
+
+ switch(skill) {
+ case SA_CASTCANCEL:
+ if(sd->skilltimer == -1) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ case BS_MAXIMIZE: /* マキシマイズパワー */
+ case NV_TRICKDEAD: /* 死んだふり */
+ case TF_HIDING: /* ハイディング */
+ case AS_CLOAKING: /* クローキング */
+ case CR_AUTOGUARD: /* オートガード */
+ case CR_DEFENDER: /* ディフェンダー */
+ case ST_CHASEWALK:
+ if(sd->sc_data[SkillStatusChangeTable[skill]].timer!=-1)
+ return 1; /* 解除する場合はSP消費しない */
+ break;
+ case AL_TELEPORT:
+ case AL_WARP:
+ if(map[sd->bl.m].flag.noteleport) {
+ clif_skill_teleportmessage(sd,0);
+ return 0;
+ }
+ break;
+ case MO_CALLSPIRITS: /* 気功 */
+ if(sd->spiritball >= lv) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ case CH_SOULCOLLECT: /* 狂気功 */
+ if(sd->spiritball >= 5) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ case MO_FINGEROFFENSIVE: //指弾
+ if (sd->spiritball > 0 && sd->spiritball < spiritball) {
+ spiritball = sd->spiritball;
+ sd->spiritball_old = sd->spiritball;
+ }
+ else sd->spiritball_old = lv;
+ break;
+ case MO_CHAINCOMBO: //連打掌
+ if(sd->sc_data[SC_BLADESTOP].timer==-1){
+ if(sd->sc_data[SC_COMBO].timer == -1 || sd->sc_data[SC_COMBO].val1 != MO_TRIPLEATTACK)
+ return 0;
+ }
+ break;
+ case MO_COMBOFINISH: //猛龍拳
+ if(sd->sc_data[SC_COMBO].timer == -1 || sd->sc_data[SC_COMBO].val1 != MO_CHAINCOMBO)
+ return 0;
+ break;
+ case CH_TIGERFIST: //伏虎拳
+ if(sd->sc_data[SC_COMBO].timer == -1 || sd->sc_data[SC_COMBO].val1 != MO_COMBOFINISH)
+ return 0;
+ break;
+ case CH_CHAINCRUSH: //連柱崩撃
+ if(sd->sc_data[SC_COMBO].timer == -1)
+ return 0;
+ if(sd->sc_data[SC_COMBO].val1 != MO_COMBOFINISH && sd->sc_data[SC_COMBO].val1 != CH_TIGERFIST)
+ return 0;
+ break;
+ case MO_EXTREMITYFIST: // 阿修羅覇鳳拳
+ if((sd->sc_data[SC_COMBO].timer != -1 && (sd->sc_data[SC_COMBO].val1 == MO_COMBOFINISH || sd->sc_data[SC_COMBO].val1 == CH_CHAINCRUSH)) || sd->sc_data[SC_BLADESTOP].timer!=-1)
+ spiritball--;
+ break;
+ case BD_ADAPTATION: /* アドリブ */
+ {
+ struct skill_unit_group *group=NULL;
+ if(sd->sc_data[SC_DANCING].timer==-1 || ((group=(struct skill_unit_group*)sd->sc_data[SC_DANCING].val2) && (skill_get_time(sd->sc_data[SC_DANCING].val1,group->skill_lv) - sd->sc_data[SC_DANCING].val3*1000) <= skill_get_time2(skill,lv))){ //ダンス中で使用後5秒以上のみ?
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ }
+ break;
+ case PR_BENEDICTIO: /* 聖体降福 */
+ {
+ int range=1;
+ int c=0;
+ if(!(type&1)){
+ map_foreachinarea(skill_check_condition_char_sub,sd->bl.m,
+ sd->bl.x-range,sd->bl.y-range,
+ sd->bl.x+range,sd->bl.y+range,BL_PC,&sd->bl,&c);
+ if(c<2){
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ }else{
+ map_foreachinarea(skill_check_condition_use_sub,sd->bl.m,
+ sd->bl.x-range,sd->bl.y-range,
+ sd->bl.x+range,sd->bl.y+range,BL_PC,&sd->bl,&c);
+ }
+ }
+ break;
+ case WE_CALLPARTNER: /* あなたに逢いたい */
+ if(!sd->status.partner_id){
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ case AM_CANNIBALIZE: /* バイオプラント */
+ case AM_SPHEREMINE: /* スフィアーマイン */
+ if(type&1){
+ int c=0;
+ int maxcount=skill_get_maxcount(skill);
+ int mob_class=(skill==AM_CANNIBALIZE)?1118:1142;
+ if(battle_config.pc_land_skill_limit && maxcount>0) {
+ map_foreachinarea(skill_check_condition_mob_master_sub ,sd->bl.m, 0, 0, map[sd->bl.m].xs, map[sd->bl.m].ys, BL_MOB, sd->bl.id, mob_class,&c );
+ if(c >= maxcount){
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ }
+ }
+ break;
+ case MG_FIREWALL: /* ファイアーウォール */
+ /* 数制限 */
+ if(battle_config.pc_land_skill_limit) {
+ int maxcount = skill_get_maxcount(skill);
+ if(maxcount > 0) {
+ int i,c;
+ for(i=c=0;i<MAX_SKILLUNITGROUP;i++) {
+ if(sd->skillunit[i].alive_count > 0 && sd->skillunit[i].skill_id == skill)
+ c++;
+ }
+ if(c >= maxcount) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ }
+ }
+ break;
+ }
+
+ if(!(type&2)){
+ if( hp>0 && sd->status.hp < hp) { /* HPチェック */
+ clif_skill_fail(sd,skill,2,0); /* HP不足:失敗通知 */
+ return 0;
+ }
+ if( sp>0 && sd->status.sp < sp) { /* SPチェック */
+ clif_skill_fail(sd,skill,1,0); /* SP不足:失敗通知 */
+ return 0;
+ }
+ if( zeny>0 && sd->status.zeny < zeny) {
+ clif_skill_fail(sd,skill,5,0);
+ return 0;
+ }
+ if(!(weapon & (1<<sd->status.weapon) ) ) {
+ clif_skill_fail(sd,skill,6,0);
+ return 0;
+ }
+ if( spiritball > 0 && sd->spiritball < spiritball) {
+ clif_skill_fail(sd,skill,0,0); // 氣球不足
+ return 0;
+ }
+ }
+
+ switch(state) {
+ case ST_HIDING:
+ if(!(sd->status.option&2)) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ case ST_CLOAKING:
+ if(!(sd->status.option&4)) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ case ST_HIDDEN:
+ if(!pc_ishiding(sd)) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ case ST_RIDING:
+ if(!pc_isriding(sd)) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ case ST_FALCON:
+ if(!pc_isfalcon(sd)) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ case ST_CART:
+ if(!pc_iscarton(sd)) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ case ST_SHIELD:
+ if(sd->status.shield <= 0) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ case ST_SIGHT:
+ if(sd->sc_data[SC_SIGHT].timer == -1 && type&1) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ case ST_EXPLOSIONSPIRITS:
+ if(sd->sc_data[SC_EXPLOSIONSPIRITS].timer == -1) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ case ST_RECOV_WEIGHT_RATE:
+ if(battle_config.natural_heal_weight_rate <= 100 && sd->weight*100/sd->max_weight >= battle_config.natural_heal_weight_rate) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ case ST_MOVE_ENABLE:
+ {
+ struct walkpath_data wpd;
+ if(path_search(&wpd,sd->bl.m,sd->bl.x,sd->bl.y,sd->skillx,sd->skilly,1)==-1) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ }
+ break;
+ case ST_WATER:
+ if(map_getcell(sd->bl.m,sd->bl.x,sd->bl.y) != 3 && (sd->sc_data[SC_DELUGE].timer==-1)){ //水場判定
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ }
+
+ for(i=0;i<10;i++) {
+ int x = lv%11 - 1;
+ index[i] = -1;
+ if(itemid[i] <= 0)
+ continue;
+ if(itemid[i] >= 715 && itemid[i] <= 717 && sd->special_state.no_gemstone)
+ continue;
+ if(((itemid[i] >= 715 && itemid[i] <= 717) || itemid[i] == 1065) && sd->sc_data[SC_INTOABYSS].timer != -1)
+ continue;
+ if(skill == AM_POTIONPITCHER && i != x)
+ continue;
+
+ index[i] = pc_search_inventory(sd,itemid[i]);
+ if(index[i] < 0 || sd->status.inventory[index[i]].amount < amount[i]) {
+ if(itemid[i] == 716 || itemid[i] == 717)
+ clif_skill_fail(sd,skill,(7+(itemid[i]-716)),0);
+ else
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ }
+
+ if(!(type&1))
+ return 1;
+
+ if(skill != AM_POTIONPITCHER) {
+ if(skill == AL_WARP && !(type&2))
+ return 1;
+ for(i=0;i<10;i++) {
+ if(index[i] >= 0)
+ pc_delitem(sd,index[i],amount[i],0); // アイテム消費
+ }
+ }
+
+ if(type&2)
+ return 1;
+
+ if(sp > 0) { // SP消費
+ sd->status.sp-=sp;
+ clif_updatestatus(sd,SP_SP);
+ }
+ if(hp > 0) { // HP消費
+ sd->status.hp-=hp;
+ clif_updatestatus(sd,SP_HP);
+ }
+ if(zeny > 0) // Zeny消費
+ pc_payzeny(sd,zeny);
+ if(spiritball > 0) // 氣球消費
+ pc_delspiritball(sd,spiritball,0);
+
+
+ return 1;
+}
+
+/*==========================================
+ * 詠唱時間計算
+ *------------------------------------------
+ */
+int skill_castfix( struct block_list *bl, int time )
+{
+ struct map_session_data *sd;
+ struct mob_data *md; // [Valaris]
+ struct status_change *sc_data;
+ int dex;
+ int castrate=100;
+ int skill,lv,castnodex;
+
+ nullpo_retr(0, bl);
+
+ if(bl->type==BL_MOB){ // Crash fix [Valaris]
+ md=(struct mob_data*)bl;
+ skill = md->skillid;
+ lv = md->skilllv;
+ }
+
+ else {
+ sd=(struct map_session_data*)bl;
+ skill = sd->skillid;
+ lv = sd->skilllv;
+ }
+
+ sc_data = battle_get_sc_data(bl);
+ dex=battle_get_dex(bl);
+
+ if (skill > MAX_SKILL_DB || skill < 0)
+ return 0;
+
+ castnodex=skill_get_castnodex(skill, lv);
+
+ if(time==0)
+ return 0;
+ if(castnodex > 0 && bl->type==BL_PC)
+ castrate=((struct map_session_data *)bl)->castrate;
+ else if (castnodex <= 0 && bl->type==BL_PC) {
+ castrate=((struct map_session_data *)bl)->castrate;
+ time=time*castrate*(battle_config.castrate_dex_scale - dex)/(battle_config.castrate_dex_scale * 100);
+ time=time*battle_config.cast_rate/100;
+ }
+
+ /* サフラギウム */
+ if(sc_data && sc_data[SC_SUFFRAGIUM].timer!=-1 ){
+ time=time*(100-sc_data[SC_SUFFRAGIUM].val1*15)/100;
+ skill_status_change_end( bl, SC_SUFFRAGIUM, -1);
+ }
+ /* ブラギの詩 */
+ if(sc_data && sc_data[SC_POEMBRAGI].timer!=-1 )
+ time=time*(100-(sc_data[SC_POEMBRAGI].val1*3+sc_data[SC_POEMBRAGI].val2
+ +(sc_data[SC_POEMBRAGI].val3>>16)))/100;
+
+ return (time>0)?time:0;
+}
+/*==========================================
+ * ディレイ計算
+ *------------------------------------------
+ */
+int skill_delayfix( struct block_list *bl, int time )
+{
+ struct status_change *sc_data;
+
+ nullpo_retr(0, bl);
+
+ sc_data = battle_get_sc_data(bl);
+ if(time<=0)
+ return 0;
+
+ if(bl->type == BL_PC) {
+ if( battle_config.delay_dependon_dex ) /* dexの影響を計算する */
+ time=time*(battle_config.castrate_dex_scale - battle_get_dex(bl))/battle_config.castrate_dex_scale;
+ time=time*battle_config.delay_rate/100;
+ }
+
+ /* ブラギの詩 */
+ if(sc_data && sc_data[SC_POEMBRAGI].timer!=-1 )
+ time=time*(100-(sc_data[SC_POEMBRAGI].val1*3+sc_data[SC_POEMBRAGI].val2
+ +(sc_data[SC_POEMBRAGI].val3&0xffff)))/100;
+
+ return (time>0)?time:0;
+}
+
+/*==========================================
+ * スキル使用(ID指定)
+ *------------------------------------------
+ */
+int skill_use_id( struct map_session_data *sd, int target_id,
+ int skill_num, int skill_lv)
+{
+ unsigned int tick;
+ int casttime=0,delay=0,skill,range;
+ struct map_session_data* target_sd=NULL;
+ int forcecast=0;
+ struct block_list *bl;
+ struct status_change *sc_data;
+ tick=gettick();
+
+ nullpo_retr(0, sd);
+
+ if( (bl=map_id2bl(target_id)) == NULL ){
+/* if(battle_config.error_log)
+ printf("skill target not found %d\n",target_id); */
+ return 0;
+ }
+ if(sd->bl.m != bl->m || pc_isdead(sd))
+ return 0;
+
+ if(skillnotok(skill_num, sd)) // [MouseJstr]
+ return 0;
+
+ sc_data=sd->sc_data;
+
+ /* 沈黙や異常(ただし、グリムなどの判定をする) */
+ if( sd->opt1>0 )
+ return 0;
+ if(sd->sc_data){
+ if(sc_data[SC_CHASEWALK].timer != -1) return 0;
+ if(sc_data[SC_VOLCANO].timer != -1){
+ if(skill_num==WZ_ICEWALL) return 0;
+ }
+ if(sc_data[SC_ROKISWEIL].timer!=-1){
+ if(skill_num==BD_ADAPTATION) return 0;
+ }
+ if( sd->sc_data[SC_DIVINA].timer!=-1 ||
+ sd->sc_data[SC_ROKISWEIL].timer!=-1 ||
+ (sd->sc_data[SC_AUTOCOUNTER].timer != -1 && sd->skillid != KN_AUTOCOUNTER) ||
+ sd->sc_data[SC_STEELBODY].timer != -1 ||
+ sd->sc_data[SC_BERSERK].timer != -1 ){
+ return 0; /* 状態異常や沈黙など */
+ }
+
+ if(sc_data[SC_BLADESTOP].timer != -1){
+ int lv = sc_data[SC_BLADESTOP].val1;
+ if(sc_data[SC_BLADESTOP].val2==1) return 0;//白羽された側なのでダメ
+ if(lv==1) return 0;
+ if(lv==2 && skill_num!=MO_FINGEROFFENSIVE) return 0;
+ if(lv==3 && skill_num!=MO_FINGEROFFENSIVE && skill_num!=MO_INVESTIGATE) return 0;
+ if(lv==4 && skill_num!=MO_FINGEROFFENSIVE && skill_num!=MO_INVESTIGATE && skill_num!=MO_CHAINCOMBO) return 0;
+ if(lv==5 && skill_num!=MO_FINGEROFFENSIVE && skill_num!=MO_INVESTIGATE && skill_num!=MO_CHAINCOMBO && skill_num!=MO_EXTREMITYFIST) return 0;
+ }
+ }
+
+ if(sd->status.option&4 && skill_num==TF_HIDING)
+ return 0;
+ if(sd->status.option&2 && skill_num!=TF_HIDING && skill_num!=AS_GRIMTOOTH && skill_num!=RG_BACKSTAP && skill_num!=RG_RAID )
+ return 0;
+
+ if(map[sd->bl.m].flag.gvg){ //GvGで使用できないスキル
+ switch(skill_num){
+ case SM_ENDURE:
+ case AL_TELEPORT:
+ case AL_WARP:
+ case WZ_ICEWALL:
+ case TF_BACKSLIDING:
+ case LK_BERSERK:
+ case HP_BASILICA:
+ case ST_CHASEWALK:
+ return 0;
+ }
+ }
+
+ /* 演奏/ダンス中 */
+ if( sc_data && sc_data[SC_DANCING].timer!=-1 ){
+// if(battle_config.pc_skill_log)
+// printf("dancing! %d\n",skill_num);
+ if( sc_data[SC_DANCING].val4 && skill_num!=BD_ADAPTATION ) //合奏中はアドリブ以外不可
+ return 0;
+ if(skill_num!=BD_ADAPTATION && skill_num!=BA_MUSICALSTRIKE && skill_num!=DC_THROWARROW){
+ return 0;
+ }
+ }
+
+ if(skill_get_inf2(skill_num)&0x200 && sd->bl.id == target_id)
+ return 0;
+ //直前のスキルが何か覚える必要のあるスキル
+ switch(skill_num){
+ case SA_CASTCANCEL:
+ if(sd->skillid != skill_num){ //キャストキャンセル自体は覚えない
+ sd->skillid_old = sd->skillid;
+ sd->skilllv_old = sd->skilllv;
+ break;
+ }
+ case BD_ENCORE: /* アンコール */
+ if(!sd->skillid_dance){ //前回使用した踊りがないとだめ
+ clif_skill_fail(sd,skill_num,0,0);
+ return 0;
+ }else{
+ sd->skillid_old = skill_num;
+ }
+ break;
+ }
+
+ sd->skillid = skill_num;
+ sd->skilllv = skill_lv;
+
+ switch(skill_num){ //事前にレベルが変わったりするスキル
+ case BD_LULLABY: /* 子守歌 */
+ case BD_RICHMANKIM: /* ニヨルドの宴 */
+ case BD_ETERNALCHAOS: /* 永遠の混沌 */
+ case BD_DRUMBATTLEFIELD: /* 戦太鼓の響き */
+ case BD_RINGNIBELUNGEN: /* ニーベルングの指輪 */
+ case BD_ROKISWEIL: /* ロキの叫び */
+ case BD_INTOABYSS: /* 深淵の中に */
+ case BD_SIEGFRIED: /* 不死身のジークフリード */
+ case BD_RAGNAROK: /* 神々の黄昏 */
+ case CG_MOONLIT: /* 月明りの泉に落ちる花びら */
+ {
+ int range=1;
+ int c=0;
+ map_foreachinarea(skill_check_condition_char_sub,sd->bl.m,
+ sd->bl.x-range,sd->bl.y-range,
+ sd->bl.x+range,sd->bl.y+range,BL_PC,&sd->bl,&c);
+ if(c<1){
+ clif_skill_fail(sd,skill_num,0,0);
+ return 0;
+ }else if(c==99){ //相方不要設定だった
+ ;
+ }else{
+ sd->skilllv=(c + skill_lv)/2;
+ }
+ }
+ break;
+ }
+
+ if(!skill_check_condition(sd,0)) return 0;
+
+ /* 射程と障害物チェック */
+ range = skill_get_range(skill_num,skill_lv);
+ if(range < 0)
+ range = battle_get_range(&sd->bl) - (range + 1);
+ if(!battle_check_range(&sd->bl,bl,range) )
+ return 0;
+
+ if(bl->type==BL_PC) {
+ target_sd=(struct map_session_data*)bl;
+ if(target_sd && skill_num == ALL_RESURRECTION && !pc_isdead(target_sd))
+ return 0;
+ }
+ if((skill_num != MO_CHAINCOMBO &&
+ skill_num != MO_COMBOFINISH &&
+ skill_num != MO_EXTREMITYFIST &&
+ skill_num != CH_TIGERFIST &&
+ skill_num != CH_CHAINCRUSH) ||
+ (skill_num == MO_EXTREMITYFIST && sd->state.skill_flag) )
+ pc_stopattack(sd);
+
+ casttime=skill_castfix(&sd->bl, skill_get_cast( skill_num,skill_lv) );
+ if(skill_num != SA_MAGICROD)
+ delay=skill_delayfix(&sd->bl, skill_get_delay( skill_num,skill_lv) );
+ sd->state.skillcastcancel = skill_db[skill_num].castcancel;
+
+ switch(skill_num){ /* 何か特殊な処理が必要 */
+// case AL_HEAL: /* ヒール */
+// if(battle_check_undead(battle_get_race(bl),battle_get_elem_type(bl)))
+// forcecast=1; /* ヒールアタックなら詠唱エフェクト有り */
+// break;
+ case ALL_RESURRECTION: /* リザレクション */
+ if(bl->type != BL_PC && battle_check_undead(battle_get_race(bl),battle_get_elem_type(bl))){ /* 敵がアンデッドなら */
+ forcecast=1; /* ターンアンデットと同じ詠唱時間 */
+ casttime=skill_castfix(&sd->bl, skill_get_cast(PR_TURNUNDEAD,skill_lv) );
+ }
+ break;
+ case MO_FINGEROFFENSIVE: /* 指弾 */
+ casttime += casttime * ((skill_lv > sd->spiritball)? sd->spiritball:skill_lv);
+ break;
+ case MO_CHAINCOMBO: /*連打掌*/
+ target_id = sd->attacktarget;
+ if( sc_data && sc_data[SC_BLADESTOP].timer!=-1 ){
+ struct block_list *tbl;
+ if((tbl=(struct block_list *)sc_data[SC_BLADESTOP].val4) == NULL) //ターゲットがいない?
+ return 0;
+ target_id = tbl->id;
+ }
+ break;
+ case MO_COMBOFINISH: /*猛龍拳*/
+ case CH_TIGERFIST: /* 伏虎拳 */
+ case CH_CHAINCRUSH: /* 連柱崩撃 */
+ target_id = sd->attacktarget;
+ break;
+
+// -- moonsoul (altered to allow proper usage of extremity from new champion combos)
+//
+ case MO_EXTREMITYFIST: /*阿修羅覇鳳拳*/
+ if(sc_data && sc_data[SC_COMBO].timer != -1 && (sc_data[SC_COMBO].val1 == MO_COMBOFINISH || sc_data[SC_COMBO].val1 == CH_CHAINCRUSH)) {
+ casttime = 0;
+ target_id = sd->attacktarget;
+ }
+ forcecast=1;
+ break;
+ case SA_MAGICROD:
+ case SA_SPELLBREAKER:
+ forcecast=1;
+ break;
+ case WE_MALE:
+ case WE_FEMALE:
+ {
+ struct map_session_data *p_sd = NULL;
+ if((p_sd = pc_get_partner(sd)) == NULL)
+ return 0;
+ target_id = p_sd->bl.id;
+ //rangeをもう1回検査
+ range = skill_get_range(skill_num,skill_lv);
+ if(range < 0)
+ range = battle_get_range(&sd->bl) - (range + 1);
+ if(!battle_check_range(&sd->bl,&p_sd->bl,range) ){
+ return 0;
+ }
+ }
+ break;
+ case AS_SPLASHER: /* ベナムスプラッシャー */
+ {
+ struct status_change *t_sc_data = battle_get_sc_data(bl);
+ if(t_sc_data && t_sc_data[SC_POISON].timer==-1){
+ clif_skill_fail(sd,skill_num,0,10);
+ return 0;
+ }
+ }
+ break;
+ case PF_MEMORIZE: /* メモライズ */
+ casttime = 12000;
+ break;
+
+ }
+
+ //メモライズ状態ならキャストタイムが1/3
+ if(sc_data && sc_data[SC_MEMORIZE].timer != -1 && casttime > 0){
+ casttime = casttime/3;
+ if((--sc_data[SC_MEMORIZE].val2)<=0)
+ skill_status_change_end(&sd->bl, SC_MEMORIZE, -1);
+ }
+
+ if(battle_config.pc_skill_log)
+ printf("PC %d skill use target_id=%d skill=%d lv=%d cast=%d\n",sd->bl.id,target_id,skill_num,skill_lv,casttime);
+
+// if(sd->skillitem == skill_num)
+// casttime = delay = 0;
+
+ if( casttime>0 || forcecast ){ /* 詠唱が必要 */
+ struct mob_data *md;
+ clif_skillcasting( &sd->bl,
+ sd->bl.id, target_id, 0,0, skill_num,casttime);
+
+ /* 詠唱反応モンスター */
+ if( bl->type==BL_MOB && (md=(struct mob_data *)bl) && mob_db[md->class].mode&0x10 &&
+ md->state.state!=MS_ATTACK && sd->invincible_timer == -1){
+ md->target_id=sd->bl.id;
+ md->state.targettype = ATTACKABLE;
+ md->min_chase=13;
+ }
+ }
+
+ if( casttime<=0 ) /* 詠唱の無いものはキャンセルされない */
+ sd->state.skillcastcancel=0;
+
+ sd->skilltarget = target_id;
+/* sd->cast_target_bl = bl; */
+ sd->skillx = 0;
+ sd->skilly = 0;
+ sd->canact_tick = tick + casttime + delay;
+ sd->canmove_tick = tick;
+ if(!(battle_config.pc_cloak_check_type&2) && sc_data && sc_data[SC_CLOAKING].timer != -1 && sd->skillid != AS_CLOAKING)
+ skill_status_change_end(&sd->bl,SC_CLOAKING,-1);
+ if(casttime > 0) {
+ sd->skilltimer = add_timer( tick+casttime, skill_castend_id, sd->bl.id, 0 );
+ if((skill = pc_checkskill(sd,SA_FREECAST)) > 0) {
+ sd->prev_speed = sd->speed;
+ sd->speed = sd->speed*(175 - skill*5)/100;
+ clif_updatestatus(sd,SP_SPEED);
+ }
+ else
+ pc_stop_walking(sd,0);
+ }
+ else {
+ if(skill_num != SA_CASTCANCEL)
+ sd->skilltimer = -1;
+ skill_castend_id(sd->skilltimer,tick,sd->bl.id,0);
+ }
+
+ //マジックパワーの効果終了
+ if(sc_data && sc_data[SC_MAGICPOWER].timer != -1 && skill_num != HW_MAGICPOWER)
+ skill_status_change_end(&sd->bl,SC_MAGICPOWER,-1);
+
+ return 0;
+}
+
+/*==========================================
+ * スキル使用(場所指定)
+ *------------------------------------------
+ */
+int skill_use_pos( struct map_session_data *sd,
+ int skill_x, int skill_y, int skill_num, int skill_lv)
+{
+ struct block_list bl;
+ struct status_change *sc_data;
+ unsigned int tick;
+ int casttime=0,delay=0,skill,range;
+
+ nullpo_retr(0, sd);
+
+ if(pc_isdead(sd))
+ return 0;
+
+ if (skillnotok(skill_num, sd)) // [MoueJstr]
+ return 0;
+
+ if(skill_num==WZ_ICEWALL && map[sd->bl.m].flag.noicewall && !map[sd->bl.m].flag.pvp) { // noicewall flag [Valaris]
+ clif_skill_fail(sd,sd->skillid,0,0);
+ return 0;
+ }
+
+ sc_data=sd->sc_data;
+
+ if( sd->opt1>0 )
+ return 0;
+ if(sc_data){
+ if( sc_data[SC_DIVINA].timer!=-1 ||
+ sc_data[SC_ROKISWEIL].timer!=-1 ||
+ sc_data[SC_AUTOCOUNTER].timer != -1 ||
+ sc_data[SC_STEELBODY].timer != -1 ||
+ sc_data[SC_DANCING].timer!=-1 ||
+ sc_data[SC_BERSERK].timer != -1 )
+ return 0; /* 状態異常や沈黙など */
+ }
+
+ if(sd->status.option&2)
+ return 0;
+
+ if(map[sd->bl.m].flag.gvg && (skill_num == SM_ENDURE || skill_num == AL_TELEPORT || skill_num == AL_WARP ||
+ skill_num == WZ_ICEWALL || skill_num == TF_BACKSLIDING))
+ return 0;
+
+ sd->skillid = skill_num;
+ sd->skilllv = skill_lv;
+ sd->skillx = skill_x;
+ sd->skilly = skill_y;
+ if(!skill_check_condition(sd,0)) return 0;
+
+ /* 射程と障害物チェック */
+ bl.type = BL_NUL;
+ bl.m = sd->bl.m;
+ bl.x = skill_x;
+ bl.y = skill_y;
+ range = skill_get_range(skill_num,skill_lv);
+ if(range < 0)
+ range = battle_get_range(&sd->bl) - (range + 1);
+ if(!battle_check_range(&sd->bl,&bl,range) )
+ return 0;
+
+ pc_stopattack(sd);
+
+ casttime=skill_castfix(&sd->bl, skill_get_cast( skill_num,skill_lv) );
+ delay=skill_delayfix(&sd->bl, skill_get_delay( skill_num,skill_lv) );
+ sd->state.skillcastcancel = skill_db[skill_num].castcancel;
+
+ if(battle_config.pc_skill_log)
+ printf("PC %d skill use target_pos=(%d,%d) skill=%d lv=%d cast=%d\n",sd->bl.id,skill_x,skill_y,skill_num,skill_lv,casttime);
+
+// if(sd->skillitem == skill_num)
+// casttime = delay = 0;
+ //メモライズ状態ならキャストタイムが1/3
+ if(sc_data && sc_data[SC_MEMORIZE].timer != -1 && casttime > 0){
+ casttime = casttime/3;
+ if((--sc_data[SC_MEMORIZE].val2)<=0)
+ skill_status_change_end(&sd->bl, SC_MEMORIZE, -1);
+ }
+
+ if( casttime>0 ) /* 詠唱が必要 */
+ clif_skillcasting( &sd->bl,
+ sd->bl.id, 0, skill_x,skill_y, skill_num,casttime);
+
+ if( casttime<=0 ) /* 詠唱の無いものはキャンセルされない */
+ sd->state.skillcastcancel=0;
+
+ sd->skilltarget = 0;
+/* sd->cast_target_bl = NULL; */
+ tick=gettick();
+ sd->canact_tick = tick + casttime + delay;
+ sd->canmove_tick = tick;
+ if(!(battle_config.pc_cloak_check_type&2) && sc_data && sc_data[SC_CLOAKING].timer != -1)
+ skill_status_change_end(&sd->bl,SC_CLOAKING,-1);
+ if(casttime > 0) {
+ sd->skilltimer = add_timer( tick+casttime, skill_castend_pos, sd->bl.id, 0 );
+ if((skill = pc_checkskill(sd,SA_FREECAST)) > 0) {
+ sd->prev_speed = sd->speed;
+ sd->speed = sd->speed*(175 - skill*5)/100;
+ clif_updatestatus(sd,SP_SPEED);
+ }
+ else
+ pc_stop_walking(sd,0);
+ }
+ else {
+ sd->skilltimer = -1;
+ skill_castend_pos(sd->skilltimer,tick,sd->bl.id,0);
+ }
+ //マジックパワーの効果終了
+ if(sc_data && sc_data[SC_MAGICPOWER].timer != -1 && skill_num != HW_MAGICPOWER)
+ skill_status_change_end(&sd->bl,SC_MAGICPOWER,-1);
+
+ return 0;
+}
+
+/*==========================================
+ * スキル詠唱キャンセル
+ *------------------------------------------
+ */
+int skill_castcancel(struct block_list *bl,int type)
+{
+ int inf;
+ int ret=0;
+
+ nullpo_retr(0, bl);
+
+ if(bl->type==BL_PC){
+ struct map_session_data *sd=(struct map_session_data *)bl;
+ unsigned long tick=gettick();
+ nullpo_retr(0, sd);
+ sd->canact_tick=tick;
+ sd->canmove_tick = tick;
+ if( sd->skilltimer!=-1){
+ if(pc_checkskill(sd,SA_FREECAST) > 0) {
+ sd->speed = sd->prev_speed;
+ clif_updatestatus(sd,SP_SPEED);
+ }
+ if(!type) {
+ if((inf = skill_get_inf( sd->skillid )) == 2 || inf == 32)
+ ret=delete_timer( sd->skilltimer, skill_castend_pos );
+ else
+ ret=delete_timer( sd->skilltimer, skill_castend_id );
+ if(ret<0)
+ printf("delete timer error : skillid : %d\n",sd->skillid);
+ }
+ else {
+ if((inf = skill_get_inf( sd->skillid_old )) == 2 || inf == 32)
+ ret=delete_timer( sd->skilltimer, skill_castend_pos );
+ else
+ ret=delete_timer( sd->skilltimer, skill_castend_id );
+ if(ret<0)
+ printf("delete timer error : skillid : %d\n",sd->skillid_old);
+ }
+ sd->skilltimer=-1;
+ clif_skillcastcancel(bl);
+ }
+
+ return 0;
+ }else if(bl->type==BL_MOB){
+ struct mob_data *md=(struct mob_data *)bl;
+ nullpo_retr(0, md);
+ if( md->skilltimer!=-1 ){
+ if((inf = skill_get_inf( md->skillid )) == 2 || inf == 32)
+ ret=delete_timer( md->skilltimer, mobskill_castend_pos );
+ else
+ ret=delete_timer( md->skilltimer, mobskill_castend_id );
+ md->skilltimer=-1;
+ clif_skillcastcancel(bl);
+ }
+ if(ret<0)
+ printf("delete timer error : skillid : %d\n",md->skillid);
+ return 0;
+ }
+ return 1;
+}
+/*=========================================
+ * ブランディッシュスピア 初期範囲決定
+ *----------------------------------------
+ */
+void skill_brandishspear_first(struct square *tc,int dir,int x,int y){
+
+ nullpo_retv(tc);
+
+ if(dir == 0){
+ tc->val1[0]=x-2;
+ tc->val1[1]=x-1;
+ tc->val1[2]=x;
+ tc->val1[3]=x+1;
+ tc->val1[4]=x+2;
+ tc->val2[0]=
+ tc->val2[1]=
+ tc->val2[2]=
+ tc->val2[3]=
+ tc->val2[4]=y-1;
+ }
+ else if(dir==2){
+ tc->val1[0]=
+ tc->val1[1]=
+ tc->val1[2]=
+ tc->val1[3]=
+ tc->val1[4]=x+1;
+ tc->val2[0]=y+2;
+ tc->val2[1]=y+1;
+ tc->val2[2]=y;
+ tc->val2[3]=y-1;
+ tc->val2[4]=y-2;
+ }
+ else if(dir==4){
+ tc->val1[0]=x-2;
+ tc->val1[1]=x-1;
+ tc->val1[2]=x;
+ tc->val1[3]=x+1;
+ tc->val1[4]=x+2;
+ tc->val2[0]=
+ tc->val2[1]=
+ tc->val2[2]=
+ tc->val2[3]=
+ tc->val2[4]=y+1;
+ }
+ else if(dir==6){
+ tc->val1[0]=
+ tc->val1[1]=
+ tc->val1[2]=
+ tc->val1[3]=
+ tc->val1[4]=x-1;
+ tc->val2[0]=y+2;
+ tc->val2[1]=y+1;
+ tc->val2[2]=y;
+ tc->val2[3]=y-1;
+ tc->val2[4]=y-2;
+ }
+ else if(dir==1){
+ tc->val1[0]=x-1;
+ tc->val1[1]=x;
+ tc->val1[2]=x+1;
+ tc->val1[3]=x+2;
+ tc->val1[4]=x+3;
+ tc->val2[0]=y-4;
+ tc->val2[1]=y-3;
+ tc->val2[2]=y-1;
+ tc->val2[3]=y;
+ tc->val2[4]=y+1;
+ }
+ else if(dir==3){
+ tc->val1[0]=x+3;
+ tc->val1[1]=x+2;
+ tc->val1[2]=x+1;
+ tc->val1[3]=x;
+ tc->val1[4]=x-1;
+ tc->val2[0]=y-1;
+ tc->val2[1]=y;
+ tc->val2[2]=y+1;
+ tc->val2[3]=y+2;
+ tc->val2[4]=y+3;
+ }
+ else if(dir==5){
+ tc->val1[0]=x+1;
+ tc->val1[1]=x;
+ tc->val1[2]=x-1;
+ tc->val1[3]=x-2;
+ tc->val1[4]=x-3;
+ tc->val2[0]=y+3;
+ tc->val2[1]=y+2;
+ tc->val2[2]=y+1;
+ tc->val2[3]=y;
+ tc->val2[4]=y-1;
+ }
+ else if(dir==7){
+ tc->val1[0]=x-3;
+ tc->val1[1]=x-2;
+ tc->val1[2]=x-1;
+ tc->val1[3]=x;
+ tc->val1[4]=x+1;
+ tc->val2[1]=y;
+ tc->val2[0]=y+1;
+ tc->val2[2]=y-1;
+ tc->val2[3]=y-2;
+ tc->val2[4]=y-3;
+ }
+
+}
+
+/*=========================================
+ * ブランディッシュスピア 方向判定 範囲拡張
+ *-----------------------------------------
+ */
+void skill_brandishspear_dir(struct square *tc,int dir,int are){
+
+ int c;
+
+ nullpo_retv(tc);
+
+ for(c=0;c<5;c++){
+ if(dir==0){
+ tc->val2[c]+=are;
+ }else if(dir==1){
+ tc->val1[c]-=are; tc->val2[c]+=are;
+ }else if(dir==2){
+ tc->val1[c]-=are;
+ }else if(dir==3){
+ tc->val1[c]-=are; tc->val2[c]-=are;
+ }else if(dir==4){
+ tc->val2[c]-=are;
+ }else if(dir==5){
+ tc->val1[c]+=are; tc->val2[c]-=are;
+ }else if(dir==6){
+ tc->val1[c]+=are;
+ }else if(dir==7){
+ tc->val1[c]+=are; tc->val2[c]+=are;
+ }
+ }
+}
+
+/*==========================================
+ * ディボーション 有効確認
+ *------------------------------------------
+ */
+void skill_devotion(struct map_session_data *md,int target)
+{
+ // 総確認
+ int n;
+
+ nullpo_retv(md);
+
+ for(n=0;n<5;n++){
+ if(md->dev.val1[n]){
+ struct map_session_data *sd = map_id2sd(md->dev.val1[n]);
+ // 相手が見つからない // 相手をディボしてるのが自分じゃない // 距離が離れてる
+ if( sd == NULL || (sd->sc_data && (md->bl.id != sd->sc_data[SC_DEVOTION].val1)) || skill_devotion3(&md->bl,md->dev.val1[n])){
+ skill_devotion_end(md,sd,n);
+ }
+ }
+ }
+}
+void skill_devotion2(struct block_list *bl,int crusader)
+{
+ // 被ディボーションが歩いた時の距離チェック
+ struct map_session_data *sd = map_id2sd(crusader);
+
+ nullpo_retv(bl);
+
+ if(sd) skill_devotion3(&sd->bl,bl->id);
+}
+int skill_devotion3(struct block_list *bl,int target)
+{
+ // クルセが歩いた時の距離チェック
+ struct map_session_data *md;
+ struct map_session_data *sd;
+ int n,r=0;
+
+ nullpo_retr(1, bl);
+
+ if( (md = (struct map_session_data *)bl) == NULL || (sd = map_id2sd(target)) == NULL )
+ return 1;
+ else
+ r = distance(bl->x,bl->y,sd->bl.x,sd->bl.y);
+
+ if(pc_checkskill(sd,CR_DEVOTION)+6 < r){ // 許容範囲を超えてた
+ for(n=0;n<5;n++)
+ if(md->dev.val1[n]==target)
+ md->dev.val2[n]=0; // 離れた時は、糸を切るだけ
+ clif_devotion(md,sd->bl.id);
+ return 1;
+ }
+ return 0;
+}
+
+void skill_devotion_end(struct map_session_data *md,struct map_session_data *sd,int target)
+{
+ // クルセと被ディボキャラのリセット
+ nullpo_retv(md);
+ nullpo_retv(sd);
+
+ md->dev.val1[target]=md->dev.val2[target]=0;
+ if(sd && sd->sc_data){
+ // skill_status_change_end(sd->bl,SC_DEVOTION,-1);
+ sd->sc_data[SC_DEVOTION].val1=0;
+ sd->sc_data[SC_DEVOTION].val2=0;
+ clif_status_change(&sd->bl,SC_DEVOTION,0);
+ clif_devotion(md,sd->bl.id);
+ }
+}
+/*==========================================
+ * オートスペル
+ *------------------------------------------
+ */
+int skill_autospell(struct map_session_data *sd,int skillid)
+{
+ int skilllv;
+ int maxlv=1,lv;
+
+ nullpo_retr(0, sd);
+
+ skilllv = pc_checkskill(sd,SA_AUTOSPELL);
+
+ if(skillid==MG_NAPALMBEAT) maxlv=3;
+ else if(skillid==MG_COLDBOLT || skillid==MG_FIREBOLT || skillid==MG_LIGHTNINGBOLT){
+ if(skilllv==2) maxlv=1;
+ else if(skilllv==3) maxlv=2;
+ else if(skilllv>=4) maxlv=3;
+ }
+ else if(skillid==MG_SOULSTRIKE){
+ if(skilllv==5) maxlv=1;
+ else if(skilllv==6) maxlv=2;
+ else if(skilllv>=7) maxlv=3;
+ }
+ else if(skillid==MG_FIREBALL){
+ if(skilllv==8) maxlv=1;
+ else if(skilllv>=9) maxlv=2;
+ }
+ else if(skillid==MG_FROSTDIVER) maxlv=1;
+ else return 0;
+
+ if(maxlv > (lv=pc_checkskill(sd,skillid)))
+ maxlv = lv;
+
+ skill_status_change_start(&sd->bl,SC_AUTOSPELL,skilllv,skillid,maxlv,0, // val1:スキルID val2:使用最大Lv
+ skill_get_time(SA_AUTOSPELL,skilllv),0);// にしてみたけどbscriptが書き易い・・・?
+ return 0;
+}
+
+/*==========================================
+ * ギャングスターパラダイス判定処理(foreachinarea)
+ *------------------------------------------
+ */
+
+static int skill_gangster_count(struct block_list *bl,va_list ap)
+{
+ int *c;
+ struct map_session_data *sd;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+
+ sd=(struct map_session_data*)bl;
+ c=va_arg(ap,int *);
+
+ if(sd && c && pc_issit(sd) && pc_checkskill(sd,RG_GANGSTER) > 0)
+ (*c)++;
+ return 0;
+}
+
+static int skill_gangster_in(struct block_list *bl,va_list ap)
+{
+ struct map_session_data *sd;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+
+ sd=(struct map_session_data*)bl;
+ if(sd && pc_issit(sd) && pc_checkskill(sd,RG_GANGSTER) > 0)
+ sd->state.gangsterparadise=1;
+ return 0;
+}
+
+static int skill_gangster_out(struct block_list *bl,va_list ap)
+{
+ struct map_session_data *sd;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+
+ sd=(struct map_session_data*)bl;
+ if(sd && sd->state.gangsterparadise)
+ sd->state.gangsterparadise=0;
+ return 0;
+}
+
+int skill_gangsterparadise(struct map_session_data *sd ,int type)
+{
+ int range=1;
+ int c=0;
+
+ nullpo_retr(0, sd);
+
+ if(pc_checkskill(sd,RG_GANGSTER) <= 0)
+ return 0;
+
+ if(type==1) {/* 座った時の処理 */
+ map_foreachinarea(skill_gangster_count,sd->bl.m,
+ sd->bl.x-range,sd->bl.y-range,
+ sd->bl.x+range,sd->bl.y+range,BL_PC,&c);
+ if(c > 0) {/*ギャングスター成功したら自分にもギャングスター属性付与*/
+ map_foreachinarea(skill_gangster_in,sd->bl.m,
+ sd->bl.x-range,sd->bl.y-range,
+ sd->bl.x+range,sd->bl.y+range,BL_PC);
+ sd->state.gangsterparadise = 1;
+ }
+ return 0;
+ }
+ else if(type==0) {/* 立ち上がったときの処理 */
+ map_foreachinarea(skill_gangster_count,sd->bl.m,
+ sd->bl.x-range,sd->bl.y-range,
+ sd->bl.x+range,sd->bl.y+range,BL_PC,&c);
+ if(c < 1)
+ map_foreachinarea(skill_gangster_out,sd->bl.m,
+ sd->bl.x-range,sd->bl.y-range,
+ sd->bl.x+range,sd->bl.y+range,BL_PC);
+ sd->state.gangsterparadise = 0;
+ return 0;
+ }
+ return 0;
+}
+/*==========================================
+ * 寒いジョーク・スクリーム判定処理(foreachinarea)
+ *------------------------------------------
+ */
+int skill_frostjoke_scream(struct block_list *bl,va_list ap)
+{
+ struct block_list *src;
+ int skillnum,skilllv;
+ unsigned int tick;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, src=va_arg(ap,struct block_list*));
+
+ skillnum=va_arg(ap,int);
+ skilllv=va_arg(ap,int);
+ tick=va_arg(ap,unsigned int);
+
+ if(src == bl)//自分には効かない
+ return 0;
+
+ if(battle_check_target(src,bl,BCT_ENEMY) > 0)
+ skill_additional_effect(src,bl,skillnum,skilllv,BF_MISC,tick);
+ else if(battle_check_target(src,bl,BCT_PARTY) > 0) {
+ if(rand()%100 < 10)//PTメンバにも低確率でかかる(とりあえず10%)
+ skill_additional_effect(src,bl,skillnum,skilllv,BF_MISC,tick);
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *アブラカダブラの使用スキル決定(決定スキルがダメなら0を返す)
+ *------------------------------------------
+ */
+int skill_abra_dataset(int skilllv)
+{
+ int skill = rand()%331;
+ //dbに基づくレベル・確率判定
+ if(skill_abra_db[skill].req_lv > skilllv || rand()%10000 >= skill_abra_db[skill].per) return 0;
+ //NPCスキルはダメ
+ if(skill >= NPC_PIERCINGATT && skill <= NPC_SUMMONMONSTER) return 0;
+ //演奏スキルはダメ
+ if(skill_is_danceskill(skill)) return 0;
+
+ return skill;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int skill_attack_area(struct block_list *bl,va_list ap)
+{
+ struct block_list *src,*dsrc;
+ int atk_type,skillid,skilllv,flag,type;
+ unsigned int tick;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+
+ atk_type = va_arg(ap,int);
+ if((src=va_arg(ap,struct block_list*)) == NULL)
+ return 0;
+ if((dsrc=va_arg(ap,struct block_list*)) == NULL)
+ return 0;
+ skillid=va_arg(ap,int);
+ skilllv=va_arg(ap,int);
+ tick=va_arg(ap,unsigned int);
+ flag=va_arg(ap,int);
+ type=va_arg(ap,int);
+
+ if(battle_check_target(dsrc,bl,type) > 0)
+ skill_attack(atk_type,src,dsrc,bl,skillid,skilllv,tick,flag);
+
+ return 0;
+}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int skill_clear_element_field(struct block_list *bl)
+{
+ struct mob_data *md=NULL;
+ struct map_session_data *sd=NULL;
+ int i,skillid;
+
+ nullpo_retr(0, bl);
+
+ if(bl->type==BL_MOB)
+ md=(struct mob_data *)bl;
+ if(bl->type==BL_PC)
+ sd=(struct map_session_data *)bl;
+
+ for(i=0;i<MAX_MOBSKILLUNITGROUP;i++){
+ if(sd){
+ skillid=sd->skillunit[i].skill_id;
+ if(skillid==SA_DELUGE||skillid==SA_VOLCANO||skillid==SA_VIOLENTGALE||skillid==SA_LANDPROTECTOR)
+ skill_delunitgroup(&sd->skillunit[i]);
+ }else if(md){
+ skillid=md->skillunit[i].skill_id;
+ if(skillid==SA_DELUGE||skillid==SA_VOLCANO||skillid==SA_VIOLENTGALE||skillid==SA_LANDPROTECTOR)
+ skill_delunitgroup(&md->skillunit[i]);
+ }
+ }
+ return 0;
+}
+/*==========================================
+ * ランドプロテクターチェック(foreachinarea)
+ *------------------------------------------
+ */
+int skill_landprotector(struct block_list *bl, va_list ap )
+{
+ int skillid;
+ int *alive;
+ struct skill_unit *unit;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+
+ skillid=va_arg(ap,int);
+ alive=va_arg(ap,int *);
+ if((unit=(struct skill_unit *)bl) == NULL)
+ return 0;
+
+ if(skillid==SA_LANDPROTECTOR){
+ skill_delunit(unit);
+ }else{
+ if(alive && unit->group->skill_id==SA_LANDPROTECTOR)
+ (*alive)=0;
+ }
+ return 0;
+}
+/*==========================================
+ * イドゥンの林檎の回復処理(foreachinarea)
+ *------------------------------------------
+ */
+int skill_idun_heal(struct block_list *bl, va_list ap )
+{
+ struct skill_unit *unit;
+ struct skill_unit_group *sg;
+ int heal;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, unit = va_arg(ap,struct skill_unit *));
+ nullpo_retr(0, sg = unit->group);
+
+ heal=30+sg->skill_lv*5+((sg->val1)>>16)*5+((sg->val1)&0xfff)/2;
+
+ if(bl->type == BL_SKILL || bl->id == sg->src_id)
+ return 0;
+
+ if(bl->type == BL_PC || bl->type == BL_MOB){
+ clif_skill_nodamage(&unit->bl,bl,AL_HEAL,heal,1);
+ battle_heal(NULL,bl,heal,0,0);
+ }
+ return 0;
+}
+
+/*==========================================
+ * 指定範囲内でsrcに対して有効なターゲットのblの数を数える(foreachinarea)
+ *------------------------------------------
+ */
+int skill_count_target(struct block_list *bl, va_list ap ){
+ struct block_list *src;
+ int *c;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+
+ if((src = va_arg(ap,struct block_list *)) == NULL)
+ return 0;
+ if((c = va_arg(ap,int *)) == NULL)
+ return 0;
+ if(battle_check_target(src,bl,BCT_ENEMY) > 0)
+ (*c)++;
+ return 0;
+}
+/*==========================================
+ * トラップ範囲処理(foreachinarea)
+ *------------------------------------------
+ */
+int skill_trap_splash(struct block_list *bl, va_list ap )
+{
+ struct block_list *src;
+ int tick;
+ int splash_count;
+ struct skill_unit *unit;
+ struct skill_unit_group *sg;
+ struct block_list *ss;
+ int i;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, src = va_arg(ap,struct block_list *));
+ nullpo_retr(0, unit = (struct skill_unit *)src);
+ nullpo_retr(0, sg = unit->group);
+ nullpo_retr(0, ss = map_id2bl(sg->src_id));
+
+ tick = va_arg(ap,int);
+ splash_count = va_arg(ap,int);
+
+ if(battle_check_target(src,bl,BCT_ENEMY) > 0){
+ switch(sg->unit_id){
+ case 0x95: /* サンドマン */
+ case 0x96: /* フラッシャー */
+ case 0x94: /* ショックウェーブトラップ */
+ skill_additional_effect(ss,bl,sg->skill_id,sg->skill_lv,BF_MISC,tick);
+ break;
+ case 0x8f: /* ブラストマイン */
+ case 0x98: /* クレイモアートラップ */
+ for(i=0;i<splash_count;i++){
+ skill_attack(BF_MISC,ss,src,bl,sg->skill_id,sg->skill_lv,tick,(sg->val2)?0x0500:0);
+ }
+ case 0x97: /* フリージングトラップ */
+ skill_attack(BF_WEAPON, ss,src,bl,sg->skill_id,sg->skill_lv,tick,(sg->val2)?0x0500:0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+/*----------------------------------------------------------------------------
+ * ステータス異常
+ *----------------------------------------------------------------------------
+ */
+
+/*==========================================
+ * ステータス異常タイマー範囲処理
+ *------------------------------------------
+ */
+int skill_status_change_timer_sub(struct block_list *bl, va_list ap )
+{
+ struct block_list *src;
+ int type;
+ unsigned int tick;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, src=va_arg(ap,struct block_list*));
+ type=va_arg(ap,int);
+ tick=va_arg(ap,unsigned int);
+
+ if(bl->type!=BL_PC && bl->type!=BL_MOB)
+ return 0;
+
+ switch( type ){
+ case SC_SIGHT: /* サイト */
+ case SC_CONCENTRATE:
+ if( (*battle_get_option(bl))&6 ){
+ skill_status_change_end( bl, SC_HIDING, -1);
+ skill_status_change_end( bl, SC_CLOAKING, -1);
+ }
+ break;
+ case SC_RUWACH: /* ルアフ */
+ if( (*battle_get_option(bl))&6 ){
+ skill_status_change_end( bl, SC_HIDING, -1);
+ skill_status_change_end( bl, SC_CLOAKING, -1);
+ if(battle_check_target( src,bl, BCT_ENEMY ) > 0) {
+ struct status_change *sc_data = battle_get_sc_data(bl);
+ skill_attack(BF_MAGIC,src,src,bl,AL_RUWACH,sc_data[type].val1,tick,0);
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+/*==========================================
+ * ステータス異常終了
+ *------------------------------------------
+ */
+int skill_status_change_end(struct block_list* bl, int type, int tid)
+{
+ struct status_change* sc_data;
+ int opt_flag=0, calc_flag = 0;
+ short *sc_count, *option, *opt1, *opt2, *opt3;
+
+ nullpo_retr(0, bl);
+ if(bl->type!=BL_PC && bl->type!=BL_MOB) {
+ if(battle_config.error_log)
+ printf("skill_status_change_end: neither MOB nor PC !\n");
+ return 0;
+ }
+ nullpo_retr(0, sc_data = battle_get_sc_data(bl));
+ nullpo_retr(0, sc_count = battle_get_sc_count(bl));
+ nullpo_retr(0, option = battle_get_option(bl));
+ nullpo_retr(0, opt1 = battle_get_opt1(bl));
+ nullpo_retr(0, opt2 = battle_get_opt2(bl));
+ nullpo_retr(0, opt3 = battle_get_opt3(bl));
+
+ if ((*sc_count) > 0 && sc_data[type].timer != -1 && (sc_data[type].timer == tid || tid == -1)) {
+
+ if (tid == -1) // タイマから呼ばれていないならタイマ削除をする
+ delete_timer(sc_data[type].timer,skill_status_change_timer);
+
+ /* 該当の異常を正常に戻す */
+ sc_data[type].timer=-1;
+ (*sc_count)--;
+
+ switch(type){ /* 異常の種類ごとの処理 */
+ case SC_PROVOKE: /* プロボック */
+ case SC_CONCENTRATE: /* 集中力向上 */
+ case SC_BLESSING: /* ブレッシング */
+ case SC_ANGELUS: /* アンゼルス */
+ case SC_INCREASEAGI: /* 速度上昇 */
+ case SC_DECREASEAGI: /* 速度減少 */
+ case SC_SIGNUMCRUCIS: /* シグナムクルシス */
+ case SC_HIDING:
+ case SC_TWOHANDQUICKEN: /* 2HQ */
+ case SC_ADRENALINE: /* アドレナリンラッシュ */
+ case SC_ENCPOISON: /* エンチャントポイズン */
+ case SC_IMPOSITIO: /* インポシティオマヌス */
+ case SC_GLORIA: /* グロリア */
+ case SC_LOUD: /* ラウドボイス */
+ case SC_QUAGMIRE: /* クァグマイア */
+ case SC_PROVIDENCE: /* プロヴィデンス */
+ case SC_SPEARSQUICKEN: /* スピアクイッケン */
+ case SC_VOLCANO:
+ case SC_DELUGE:
+ case SC_VIOLENTGALE:
+ case SC_ETERNALCHAOS: /* エターナルカオス */
+ case SC_DRUMBATTLE: /* 戦太鼓の響き */
+ case SC_NIBELUNGEN: /* ニーベルングの指輪 */
+ case SC_SIEGFRIED: /* 不死身のジークフリード */
+ case SC_WHISTLE: /* 口笛 */
+ case SC_ASSNCROS: /* 夕陽のアサシンクロス */
+ case SC_HUMMING: /* ハミング */
+ case SC_DONTFORGETME: /* 私を忘れないで */
+ case SC_FORTUNE: /* 幸運のキス */
+ case SC_SERVICE4U: /* サービスフォーユー */
+ case SC_EXPLOSIONSPIRITS: // 爆裂波動
+ case SC_STEELBODY: // 金剛
+ case SC_DEFENDER:
+ case SC_SPEEDPOTION0: /* 増速ポーション */
+ case SC_SPEEDPOTION1:
+ case SC_SPEEDPOTION2:
+ case SC_APPLEIDUN: /* イドゥンの林檎 */
+ case SC_RIDING:
+ case SC_BLADESTOP_WAIT:
+ case SC_AURABLADE: /* オーラブレード */
+ case SC_PARRYING: /* パリイング */
+ case SC_CONCENTRATION: /* コンセントレーション */
+ case SC_TENSIONRELAX: /* テンションリラックス */
+ case SC_ASSUMPTIO: /* アシャンプティオ */
+ case SC_WINDWALK: /* ウインドウォーク */
+ case SC_TRUESIGHT: /* トゥルーサイト */
+ case SC_SPIDERWEB: /* スパイダーウェッブ */
+ case SC_MAGICPOWER: /* 魔法力増幅 */
+ case SC_CHASEWALK:
+ case SC_ATKPOT: /* attack potion [Valaris] */
+ case SC_MATKPOT: /* magic attack potion [Valaris] */
+ case SC_WEDDING: //結婚用(結婚衣裳になって歩くのが遅いとか)
+ case SC_MELTDOWN: /* メルトダウン */
+ calc_flag = 1;
+ break;
+ case SC_BERSERK: /* バーサーク */
+ calc_flag = 1;
+ clif_status_change(bl,SC_INCREASEAGI,0); /* アイコン消去 */
+ break;
+ case SC_DEVOTION: /* ディボーション */
+ {
+ struct map_session_data *md = map_id2sd(sc_data[type].val1);
+ sc_data[type].val1=sc_data[type].val2=0;
+ skill_devotion(md,bl->id);
+ calc_flag = 1;
+ }
+ break;
+ case SC_BLADESTOP:
+ {
+ struct status_change *t_sc_data = battle_get_sc_data((struct block_list *)sc_data[type].val4);
+ //片方が切れたので相手の白刃状態が切れてないのなら解除
+ if(t_sc_data && t_sc_data[SC_BLADESTOP].timer!=-1)
+ skill_status_change_end((struct block_list *)sc_data[type].val4,SC_BLADESTOP,-1);
+
+ if(sc_data[type].val2==2)
+ clif_bladestop((struct block_list *)sc_data[type].val3,(struct block_list *)sc_data[type].val4,0);
+ }
+ break;
+ case SC_DANCING:
+ {
+ struct map_session_data *dsd;
+ struct status_change *d_sc_data;
+ if(sc_data[type].val4 && (dsd=map_id2sd(sc_data[type].val4))){
+ d_sc_data = dsd->sc_data;
+ //合奏で相手がいる場合相手のval4を0にする
+ if(d_sc_data && d_sc_data[type].timer!=-1)
+ d_sc_data[type].val4=0;
+ }
+ }
+ calc_flag = 1;
+ break;
+ case SC_GRAFFITI:
+ {
+ struct skill_unit_group *sg=(struct skill_unit_group *)sc_data[type].val4; //val4がグラフィティのgroup_id
+ if(sg)
+ skill_delunitgroup(sg);
+ }
+ break;
+ case SC_NOCHAT: //チャット禁止状態
+ {
+ struct map_session_data *sd=NULL;
+ if(bl->type == BL_PC && (sd=(struct map_session_data *)bl)){
+ sd->status.manner = 0;
+ clif_updatestatus(sd,SP_MANNER);
+ }
+ }
+ break;
+ case SC_SPLASHER: /* ベナムスプラッシャー */
+ {
+ struct block_list *src=map_id2bl(sc_data[type].val3);
+ if(src && tid!=-1){
+ //自分にダメージ&周囲3*3にダメージ
+ skill_castend_damage_id(src, bl,sc_data[type].val2,sc_data[type].val1,gettick(),0 );
+ }
+ }
+ break;
+ case SC_SELFDESTRUCTION: /* 自爆 */
+ {
+ //自分のダメージは0にして
+ struct mob_data *md=NULL;
+ if(bl->type == BL_MOB && (md=(struct mob_data*)bl))
+ skill_castend_damage_id(bl, bl,sc_data[type].val2,sc_data[type].val1,gettick(),0 );
+ }
+ break;
+ /* option1 */
+ case SC_FREEZE:
+ sc_data[type].val3 = 0;
+ break;
+
+ /* option2 */
+ case SC_POISON: /* 毒 */
+ case SC_BLIND: /* 暗黒 */
+ case SC_CURSE:
+ calc_flag = 1;
+ break;
+ }
+
+ if(bl->type==BL_PC && type<SC_SENDMAX)
+ clif_status_change(bl,type,0); /* アイコン消去 */
+
+ switch(type){ /* 正常に戻るときなにか処理が必要 */
+ case SC_STONE:
+ case SC_FREEZE:
+ case SC_STAN:
+ case SC_SLEEP:
+ *opt1 = 0;
+ opt_flag = 1;
+ break;
+
+ case SC_POISON:
+ case SC_CURSE:
+ case SC_SILENCE:
+ case SC_BLIND:
+ *opt2 &= ~(1<<(type-SC_POISON));
+ opt_flag = 1;
+ break;
+
+ case SC_SIGNUMCRUCIS:
+ *opt2 &= ~0x40;
+ opt_flag = 1;
+ break;
+
+ case SC_HIDING:
+ case SC_CLOAKING:
+ *option &= ~((type == SC_HIDING) ? 2 : 4);
+ opt_flag = 1 ;
+ break;
+
+ case SC_CHASEWALK:
+ *option &= ~16388;
+ opt_flag = 1 ;
+ break;
+
+ case SC_SIGHT:
+ *option &= ~1;
+ opt_flag = 1;
+ break;
+ case SC_WEDDING: //結婚用(結婚衣裳になって歩くのが遅いとか)
+ *option &= ~4096;
+ opt_flag = 1;
+ break;
+ case SC_RUWACH:
+ *option &= ~8192;
+ opt_flag = 1;
+ break;
+
+ //opt3
+ case SC_TWOHANDQUICKEN: /* 2HQ */
+ case SC_SPEARSQUICKEN: /* スピアクイッケン */
+ case SC_CONCENTRATION: /* コンセントレーション */
+ *opt3 &= ~1;
+ break;
+ case SC_OVERTHRUST: /* オーバースラスト */
+ *opt3 &= ~2;
+ break;
+ case SC_ENERGYCOAT: /* エナジーコート */
+ *opt3 &= ~4;
+ break;
+ case SC_EXPLOSIONSPIRITS: // 爆裂波動
+ *opt3 &= ~8;
+ break;
+ case SC_STEELBODY: // 金剛
+ *opt3 &= ~16;
+ break;
+ case SC_BLADESTOP: /* 白刃取り */
+ *opt3 &= ~32;
+ break;
+ case SC_BERSERK: /* バーサーク */
+ *opt3 &= ~128;
+ break;
+ case SC_MARIONETTE: /* マリオネットコントロール */
+ *opt3 &= ~1024;
+ break;
+ case SC_ASSUMPTIO: /* アスムプティオ */
+ *opt3 &= ~2048;
+ break;
+ }
+
+ if (night_flag == 1 && (*opt2 & STATE_BLIND) == 0 && bl->type == BL_PC) { // by [Yor]
+ *opt2 |= STATE_BLIND;
+ opt_flag = 1;
+ }
+
+ if(opt_flag) /* optionの変更を伝える */
+ clif_changeoption(bl);
+
+ if (bl->type == BL_PC && calc_flag)
+ pc_calcstatus((struct map_session_data *)bl,0); /* ステータス再計算 */
+ }
+
+ return 0;
+}
+/*==========================================
+ * ステータス異常終了タイマー
+ *------------------------------------------
+ */
+int skill_status_change_timer(int tid, unsigned int tick, int id, int data)
+{
+ int type=data;
+ struct block_list *bl;
+ struct map_session_data *sd=NULL;
+ struct status_change *sc_data;
+ //short *sc_count; //使ってない?
+
+ if( (bl=map_id2bl(id)) == NULL )
+ return 0; //該当IDがすでに消滅しているというのはいかにもありそうなのでスルーしてみる
+ nullpo_retr(0, sc_data=battle_get_sc_data(bl));
+
+ if(bl->type==BL_PC)
+ sd=(struct map_session_data *)bl;
+
+ //sc_count=battle_get_sc_count(bl); //使ってない?
+
+ if(sc_data[type].timer != tid) {
+ if(battle_config.error_log)
+ printf("skill_status_change_timer %d != %d\n",tid,sc_data[type].timer);
+ }
+
+ switch(type){ /* 特殊な処理になる場合 */
+ case SC_MAXIMIZEPOWER: /* マキシマイズパワー */
+ case SC_CLOAKING:
+ if(sd){
+ if( sd->status.sp > 0 ){ /* SP切れるまで持続 */
+ sd->status.sp--;
+ clif_updatestatus(sd,SP_SP);
+ sc_data[type].timer=add_timer( /* タイマー再設定 */
+ sc_data[type].val2+tick, skill_status_change_timer, bl->id, data);
+ return 0;
+ }
+ }
+ break;
+
+ case SC_CHASEWALK:
+ if(sd){
+ if( sd->status.sp > 19+sc_data[SC_CHASEWALK].val1*3){
+ sd->status.sp-=(19+(sc_data[SC_CHASEWALK].val1*3)); // update sp cost [Celest]
+ clif_updatestatus(sd,SP_SP);
+ sc_data[type].timer=add_timer( /* タイマー再設定 */
+ sc_data[type].val2+tick, skill_status_change_timer, bl->id, data);
+ return 0;
+ }
+ }
+ break;
+
+ case SC_HIDING: /* ハイディング */
+ if(sd){ /* SPがあって、時間制限の間は持続 */
+ if( sd->status.sp > 0 && (--sc_data[type].val2)>0 ){
+ if(sc_data[type].val2 % (sc_data[type].val1+3) ==0 ){
+ sd->status.sp--;
+ clif_updatestatus(sd,SP_SP);
+ }
+ sc_data[type].timer=add_timer( /* タイマー再設定 */
+ 1000+tick, skill_status_change_timer,
+ bl->id, data);
+ return 0;
+ }
+ }
+ break;
+
+ case SC_SIGHT: /* サイト */
+ {
+ const int range=7;
+ map_foreachinarea( skill_status_change_timer_sub,
+ bl->m, bl->x-range, bl->y-range, bl->x+range,bl->y+range,0,
+ bl,type,tick);
+
+ if( (--sc_data[type].val2)>0 ){
+ sc_data[type].timer=add_timer( /* タイマー再設定 */
+ 250+tick, skill_status_change_timer,
+ bl->id, data);
+ return 0;
+ }
+ }
+ break;
+ case SC_RUWACH: /* ルアフ */
+ {
+ const int range=5;
+ map_foreachinarea( skill_status_change_timer_sub,
+ bl->m, bl->x-range, bl->y-range, bl->x+range,bl->y+range,0,
+ bl,type,tick);
+
+ if( (--sc_data[type].val2)>0 ){
+ sc_data[type].timer=add_timer( /* タイマー再設定 */
+ 250+tick, skill_status_change_timer,
+ bl->id, data);
+ return 0;
+ }
+ }
+ break;
+
+ case SC_SIGNUMCRUCIS: /* シグナムクルシス */
+ {
+ int race = battle_get_race(bl);
+ if(race == 6 || battle_check_undead(race,battle_get_elem_type(bl))) {
+ sc_data[type].timer=add_timer(1000*600+tick,skill_status_change_timer, bl->id, data );
+ return 0;
+ }
+ }
+ break;
+
+ case SC_PROVOKE: /* プロボック/オートバーサーク */
+ if(sc_data[type].val2!=0){ /* オートバーサーク(1秒ごとにHPチェック) */
+ if(sd && sd->status.hp>sd->status.max_hp>>2) /* 停止 */
+ break;
+ sc_data[type].timer=add_timer( 1000+tick,skill_status_change_timer, bl->id, data );
+ return 0;
+ }
+ break;
+
+ case SC_WATERBALL: /* ウォーターボール */
+ {
+ struct block_list *target=map_id2bl(sc_data[type].val2);
+ if(target==NULL || target->prev==NULL)
+ break;
+ skill_attack(BF_MAGIC,bl,bl,target,WZ_WATERBALL,sc_data[type].val1,tick,0);
+ if((--sc_data[type].val3)>0) {
+ sc_data[type].timer=add_timer( 150+tick,skill_status_change_timer, bl->id, data );
+ return 0;
+ }
+ }
+ break;
+
+ case SC_ENDURE: /* インデュア */
+ if(sd && sd->special_state.infinite_endure) {
+ sc_data[type].timer=add_timer( 1000*600+tick,skill_status_change_timer, bl->id, data );
+ sc_data[type].val2=1;
+ return 0;
+ }
+ break;
+
+ case SC_DISSONANCE: /* 不協和音 */
+ if( (--sc_data[type].val2)>0){
+ struct skill_unit *unit=
+ (struct skill_unit *)sc_data[type].val4;
+ struct block_list *src;
+
+ if(!unit || !unit->group)
+ break;
+ src=map_id2bl(unit->group->src_id);
+ if(!src)
+ break;
+ skill_attack(BF_MISC,src,&unit->bl,bl,unit->group->skill_id,sc_data[type].val1,tick,0);
+ sc_data[type].timer=add_timer(skill_get_time2(unit->group->skill_id,unit->group->skill_lv)+tick,
+ skill_status_change_timer, bl->id, data );
+ return 0;
+ }
+ break;
+
+ case SC_LULLABY: /* 子守唄 */
+ if( (--sc_data[type].val2)>0){
+ struct skill_unit *unit=
+ (struct skill_unit *)sc_data[type].val4;
+ if(!unit || !unit->group || unit->group->src_id==bl->id)
+ break;
+ skill_additional_effect(bl,bl,unit->group->skill_id,sc_data[type].val1,BF_LONG|BF_SKILL|BF_MISC,tick);
+ sc_data[type].timer=add_timer(skill_get_time(unit->group->skill_id,unit->group->skill_lv)/10+tick,
+ skill_status_change_timer, bl->id, data );
+ return 0;
+ }
+ break;
+
+ case SC_STONE:
+ if(sc_data[type].val2 != 0) {
+ short *opt1 = battle_get_opt1(bl);
+ sc_data[type].val2 = 0;
+ sc_data[type].val4 = 0;
+ battle_stopwalking(bl,1);
+ if(opt1) {
+ *opt1 = 1;
+ clif_changeoption(bl);
+ }
+ sc_data[type].timer=add_timer(1000+tick,skill_status_change_timer, bl->id, data );
+ return 0;
+ }
+ else if( (--sc_data[type].val3) > 0) {
+ int hp = battle_get_max_hp(bl);
+ if((++sc_data[type].val4)%5 == 0 && battle_get_hp(bl) > hp>>2) {
+ hp = hp/100;
+ if(hp < 1) hp = 1;
+ if(bl->type == BL_PC)
+ pc_heal((struct map_session_data *)bl,-hp,0);
+ else if(bl->type == BL_MOB){
+ struct mob_data *md;
+ if((md=((struct mob_data *)bl)) == NULL)
+ break;
+ md->hp -= hp;
+ }
+ }
+ sc_data[type].timer=add_timer(1000+tick,skill_status_change_timer, bl->id, data );
+ return 0;
+ }
+ break;
+ case SC_POISON:
+ if(sc_data[SC_SLOWPOISON].timer == -1) {
+ if( (--sc_data[type].val3) > 0) {
+ int hp = battle_get_max_hp(bl);
+ if(battle_get_hp(bl) > hp>>2) {
+ if(bl->type == BL_PC) {
+ hp = 3 + hp*3/200;
+ pc_heal((struct map_session_data *)bl,-hp,0);
+ }
+ else if(bl->type == BL_MOB) {
+ struct mob_data *md;
+ if((md=((struct mob_data *)bl)) == NULL)
+ break;
+ hp = 3 + hp/200;
+ md->hp -= hp;
+ }
+ }
+ sc_data[type].timer=add_timer(1000+tick,skill_status_change_timer, bl->id, data );
+ }
+ }
+ else
+ sc_data[type].timer=add_timer(1000+tick,skill_status_change_timer, bl->id, data );
+ break;
+ case SC_TENSIONRELAX: /* テンションリラックス */
+ if(sd){ /* SPがあって、HPが満タンでなければ継続 */
+ if( sd->status.sp > 12 && sd->status.max_hp > sd->status.hp ){
+ if(sc_data[type].val2 % (sc_data[type].val1+3) ==0 ){
+ sd->status.sp -= 12;
+ clif_updatestatus(sd,SP_SP);
+ }
+ sc_data[type].timer=add_timer( /* タイマー再設定 */
+ 10000+tick, skill_status_change_timer,
+ bl->id, data);
+ return 0;
+ }
+ if(sd->status.max_hp <= sd->status.hp)
+ skill_status_change_end(&sd->bl,SC_TENSIONRELAX,-1);
+ }
+ break;
+
+ /* 時間切れ無し?? */
+ case SC_AETERNA:
+ case SC_TRICKDEAD:
+ case SC_RIDING:
+ case SC_FALCON:
+ case SC_WEIGHT50:
+ case SC_WEIGHT90:
+ case SC_MAGICPOWER: /* 魔法力増幅 */
+ case SC_REJECTSWORD: /* リジェクトソード */
+ case SC_MEMORIZE: /* メモライズ */
+ case SC_BROKNWEAPON:
+ case SC_BROKNARMOR:
+ if(sc_data[type].timer==tid)
+ sc_data[type].timer=add_timer( 1000*600+tick,skill_status_change_timer, bl->id, data );
+ return 0;
+
+ case SC_DANCING: //ダンススキルの時間SP消費
+ {
+ int s=0;
+ if(sd){
+ if(sd->status.sp > 0 && (--sc_data[type].val3)>0){
+ switch(sc_data[type].val1){
+ case BD_RICHMANKIM: /* ニヨルドの宴 3秒にSP1 */
+ case BD_DRUMBATTLEFIELD: /* 戦太鼓の響き 3秒にSP1 */
+ case BD_RINGNIBELUNGEN: /* ニーベルングの指輪 3秒にSP1 */
+ case BD_SIEGFRIED: /* 不死身のジークフリード 3秒にSP1 */
+ case BA_DISSONANCE: /* 不協和音 3秒でSP1 */
+ case BA_ASSASSINCROSS: /* 夕陽のアサシンクロス 3秒でSP1 */
+ case DC_UGLYDANCE: /* 自分勝手なダンス 3秒でSP1 */
+ s=3;
+ break;
+ case BD_LULLABY: /* 子守歌 4秒にSP1 */
+ case BD_ETERNALCHAOS: /* 永遠の混沌 4秒にSP1 */
+ case BD_ROKISWEIL: /* ロキの叫び 4秒にSP1 */
+ case DC_FORTUNEKISS: /* 幸運のキス 4秒でSP1 */
+ s=4;
+ break;
+ case BD_INTOABYSS: /* 深淵の中に 5秒にSP1 */
+ case BA_WHISTLE: /* 口笛 5秒でSP1 */
+ case DC_HUMMING: /* ハミング 5秒でSP1 */
+ case BA_POEMBRAGI: /* ブラギの詩 5秒でSP1 */
+ case DC_SERVICEFORYOU: /* サービスフォーユー 5秒でSP1 */
+ s=5;
+ break;
+ case BA_APPLEIDUN: /* イドゥンの林檎 6秒でSP1 */
+ s=6;
+ break;
+ case DC_DONTFORGETME: /* 私を忘れないで… 10秒でSP1 */
+ case CG_MOONLIT: /* 月明りの泉に落ちる花びら 10秒でSP1? */
+ s=10;
+ break;
+ }
+ if(s && ((sc_data[type].val3 % s) == 0)){
+ sd->status.sp--;
+ clif_updatestatus(sd,SP_SP);
+ }
+ sc_data[type].timer=add_timer( /* タイマー再設定 */
+ 1000+tick, skill_status_change_timer,
+ bl->id, data);
+ return 0;
+ }
+ }
+ }
+ break;
+ case SC_BERSERK: /* バーサーク */
+ if(sd){ /* HPが100以上なら継続 */
+ if( (sd->status.hp - sd->status.hp/100) > 100 ){
+ sd->status.hp -= sd->status.hp/100;
+ clif_updatestatus(sd,SP_HP);
+ sc_data[type].timer=add_timer( /* タイマー再設定 */
+ 15000+tick, skill_status_change_timer,
+ bl->id, data);
+ return 0;
+ }
+ }
+ break;
+ case SC_WEDDING: //結婚用(結婚衣裳になって歩くのが遅いとか)
+ if(sd){
+ time_t timer;
+ if(time(&timer) < ((sc_data[type].val2) + 3600)){ //1時間たっていないので継続
+ sc_data[type].timer=add_timer( /* タイマー再設定 */
+ 10000+tick, skill_status_change_timer,
+ bl->id, data);
+ return 0;
+ }
+ }
+ break;
+ case SC_NOCHAT: //チャット禁止状態
+ if(sd && battle_config.muting_players){
+ time_t timer;
+ if((++sd->status.manner) && time(&timer) < ((sc_data[type].val2) + 60*(0-sd->status.manner))){ //開始からstatus.manner分経ってないので継続
+ clif_updatestatus(sd,SP_MANNER);
+ sc_data[type].timer=add_timer( /* タイマー再設定(60秒) */
+ 60000+tick, skill_status_change_timer,
+ bl->id, data);
+ return 0;
+ }
+ }
+ break;
+ case SC_SELFDESTRUCTION: /* 自爆 */
+ if(--sc_data[type].val3>0){
+ struct mob_data *md;
+ if(bl->type==BL_MOB && (md=(struct mob_data *)bl) && md->speed > 250){
+ md->speed -= 250;
+ md->next_walktime=tick;
+ }
+ sc_data[type].timer=add_timer( /* タイマー再設定 */
+ 1000+tick, skill_status_change_timer,
+ bl->id, data);
+ return 0;
+ }
+ break;
+ }
+
+ return skill_status_change_end( bl,type,tid );
+}
+
+/*==========================================
+ * ステータス異常終了
+ *------------------------------------------
+ */
+int skill_encchant_eremental_end(struct block_list *bl,int type)
+{
+ struct status_change *sc_data;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, sc_data=battle_get_sc_data(bl));
+
+ if( type!=SC_ENCPOISON && sc_data[SC_ENCPOISON].timer!=-1 ) /* エンチャントポイズン解除 */
+ skill_status_change_end(bl,SC_ENCPOISON,-1);
+ if( type!=SC_ASPERSIO && sc_data[SC_ASPERSIO].timer!=-1 ) /* アスペルシオ解除 */
+ skill_status_change_end(bl,SC_ASPERSIO,-1);
+ if( type!=SC_FLAMELAUNCHER && sc_data[SC_FLAMELAUNCHER].timer!=-1 ) /* フレイムランチャ解除 */
+ skill_status_change_end(bl,SC_FLAMELAUNCHER,-1);
+ if( type!=SC_FROSTWEAPON && sc_data[SC_FROSTWEAPON].timer!=-1 ) /* フロストウェポン解除 */
+ skill_status_change_end(bl,SC_FROSTWEAPON,-1);
+ if( type!=SC_LIGHTNINGLOADER && sc_data[SC_LIGHTNINGLOADER].timer!=-1 ) /* ライトニングローダー解除 */
+ skill_status_change_end(bl,SC_LIGHTNINGLOADER,-1);
+ if( type!=SC_SEISMICWEAPON && sc_data[SC_SEISMICWEAPON].timer!=-1 ) /* サイスミックウェポン解除 */
+ skill_status_change_end(bl,SC_SEISMICWEAPON,-1);
+
+ return 0;
+}
+/*==========================================
+ * ステータス異常開始
+ *------------------------------------------
+ */
+int skill_status_change_start(struct block_list *bl, int type, int val1, int val2, int val3, int val4, int tick, int flag)
+{
+ struct map_session_data *sd = NULL;
+ struct status_change* sc_data;
+ short *sc_count, *option, *opt1, *opt2, *opt3;
+ int opt_flag = 0, calc_flag = 0,updateflag = 0, race, mode, elem, undead_flag;
+ int scdef=0;
+
+ nullpo_retr(0, bl);
+ if(bl->type == BL_SKILL)
+ return 0;
+ nullpo_retr(0, sc_data=battle_get_sc_data(bl));
+ nullpo_retr(0, sc_count=battle_get_sc_count(bl));
+ nullpo_retr(0, option=battle_get_option(bl));
+ nullpo_retr(0, opt1=battle_get_opt1(bl));
+ nullpo_retr(0, opt2=battle_get_opt2(bl));
+ nullpo_retr(0, opt3=battle_get_opt3(bl));
+
+
+ race=battle_get_race(bl);
+ mode=battle_get_mode(bl);
+ elem=battle_get_elem_type(bl);
+ undead_flag=battle_check_undead(race,elem);
+
+ if(type == SC_AETERNA && (sc_data[SC_STONE].timer != -1 || sc_data[SC_FREEZE].timer != -1) )
+ return 0;
+
+ switch(type){
+ case SC_STONE:
+ case SC_FREEZE:
+ scdef=3+battle_get_mdef(bl)+battle_get_luk(bl)/3;
+ break;
+ case SC_STAN:
+ case SC_SILENCE:
+ case SC_POISON:
+ scdef=3+battle_get_vit(bl)+battle_get_luk(bl)/3;
+ break;
+ case SC_SLEEP:
+ case SC_BLIND:
+ scdef=3+battle_get_int(bl)+battle_get_luk(bl)/3;
+ break;
+ case SC_CURSE:
+ scdef=3+battle_get_luk(bl);
+ break;
+
+// case SC_CONFUSION:
+ default:
+ scdef=0;
+ }
+ if(scdef>=100)
+ return 0;
+ if(bl->type==BL_PC){
+ sd=(struct map_session_data *)bl;
+ if( sd && type == SC_ADRENALINE && !(skill_get_weapontype(BS_ADRENALINE)&(1<<sd->status.weapon)))
+ return 0;
+
+ if(SC_STONE<=type && type<=SC_BLIND){ /* カードによる耐性 */
+ if( sd && sd->reseff[type-SC_STONE] > 0 && rand()%10000<sd->reseff[type-SC_STONE]){
+ if(battle_config.battle_log)
+ printf("PC %d skill_sc_start: cardによる異常耐性発動\n",sd->bl.id);
+ return 0;
+ }
+ }
+ }
+ else if(bl->type == BL_MOB) {
+ }
+ else {
+ if(battle_config.error_log)
+ printf("skill_status_change_start: neither MOB nor PC !\n");
+ return 0;
+ }
+
+ if(type==SC_FREEZE && undead_flag && !(flag&1))
+ return 0;
+
+ if((type == SC_ADRENALINE || type == SC_WEAPONPERFECTION || type == SC_OVERTHRUST) &&
+ sc_data[type].timer != -1 && sc_data[type].val2 && !val2)
+ return 0;
+
+ if(mode & 0x20 && (type==SC_STONE || type==SC_FREEZE ||
+ type==SC_STAN || type==SC_SLEEP || type==SC_SILENCE || type==SC_QUAGMIRE || type == SC_DECREASEAGI || type == SC_SIGNUMCRUCIS || type == SC_PROVOKE ||
+ (type == SC_BLESSING && (undead_flag || race == 6))) && !(flag&1)){
+ /* ボスには効かない(ただしカードによる効果は適用される) */
+ return 0;
+ }
+ if(type==SC_FREEZE || type==SC_STAN || type==SC_SLEEP)
+ battle_stopwalking(bl,1);
+
+ if(sc_data[type].timer != -1){ /* すでに同じ異常になっている場合タイマ解除 */
+ if(sc_data[type].val1 > val1 && type != SC_COMBO && type != SC_DANCING && type != SC_DEVOTION &&
+ type != SC_SPEEDPOTION0 && type != SC_SPEEDPOTION1 && type != SC_SPEEDPOTION2
+ && type != SC_ATKPOT && type != SC_MATKPOT) // added atk and matk potions [Valaris]
+ return 0;
+ if(type >=SC_STAN && type <= SC_BLIND)
+ return 0;/* 継ぎ足しができない状態異常である時は状態異常を行わない */
+ if(type == SC_GRAFFITI){ //異常中にもう一度状態異常になった時に解除してから再度かかる
+ skill_status_change_end(bl,type,-1);
+ }else{
+ (*sc_count)--;
+ delete_timer(sc_data[type].timer, skill_status_change_timer);
+ sc_data[type].timer = -1;
+ }
+ }
+
+ switch(type){ /* 異常の種類ごとの処理 */
+ case SC_PROVOKE: /* プロボック */
+ calc_flag = 1;
+ if(tick <= 0) tick = 1000; /* (オートバーサーク) */
+ break;
+ case SC_ENDURE: /* インデュア */
+ if(tick <= 0) tick = 1000 * 60;
+ break;
+ case SC_CONCENTRATE: /* 集中力向上 */
+ calc_flag = 1;
+ break;
+ case SC_BLESSING: /* ブレッシング */
+ {
+ if(bl->type == BL_PC || (!undead_flag && race != 6)) {
+ if(sc_data[SC_CURSE].timer!=-1 )
+ skill_status_change_end(bl,SC_CURSE,-1);
+ if(sc_data[SC_STONE].timer!=-1 && sc_data[SC_STONE].val2 == 0)
+ skill_status_change_end(bl,SC_STONE,-1);
+ }
+ calc_flag = 1;
+ }
+ break;
+ case SC_ANGELUS: /* アンゼルス */
+ calc_flag = 1;
+ break;
+ case SC_INCREASEAGI: /* 速度上昇 */
+ calc_flag = 1;
+ if(sc_data[SC_DECREASEAGI].timer!=-1 )
+ skill_status_change_end(bl,SC_DECREASEAGI,-1);
+ if(sc_data[SC_WINDWALK].timer!=-1 ) /* ウインドウォーク */
+ skill_status_change_end(bl,SC_WINDWALK,-1);
+ break;
+ case SC_DECREASEAGI: /* 速度減少 */
+ calc_flag = 1;
+ if(sc_data[SC_INCREASEAGI].timer!=-1 )
+ skill_status_change_end(bl,SC_INCREASEAGI,-1);
+ break;
+ case SC_SIGNUMCRUCIS: /* シグナムクルシス */
+ calc_flag = 1;
+// val2 = 14 + val1;
+ val2 = 10 + val1*2;
+ tick = 600*1000;
+ clif_emotion(bl,4);
+ break;
+ case SC_SLOWPOISON:
+ if(sc_data[SC_POISON].timer == -1 )
+ return 0;
+ break;
+ case SC_TWOHANDQUICKEN: /* 2HQ */
+ *opt3 |= 1;
+ calc_flag = 1;
+ break;
+ case SC_ADRENALINE: /* アドレナリンラッシュ */
+ calc_flag = 1;
+ break;
+ case SC_WEAPONPERFECTION: /* ウェポンパーフェクション */
+ if(battle_config.party_skill_penaly && !val2) tick /= 5;
+ break;
+ case SC_OVERTHRUST: /* オーバースラスト */
+ *opt3 |= 2;
+ if(battle_config.party_skill_penaly && !val2) tick /= 10;
+ break;
+ case SC_MAXIMIZEPOWER: /* マキシマイズパワー(SPが1減る時間,val2にも) */
+ if(bl->type == BL_PC)
+ val2 = tick;
+ else
+ tick = 5000*val1;
+ break;
+ case SC_ENCPOISON: /* エンチャントポイズン */
+ calc_flag = 1;
+ val2=(((val1 - 1) / 2) + 3)*100; /* 毒付与確率 */
+ skill_encchant_eremental_end(bl,SC_ENCPOISON);
+ break;
+ case SC_POISONREACT: /* ポイズンリアクト */
+ break;
+ case SC_IMPOSITIO: /* インポシティオマヌス */
+ calc_flag = 1;
+ break;
+ case SC_ASPERSIO: /* アスペルシオ */
+ skill_encchant_eremental_end(bl,SC_ASPERSIO);
+ break;
+ case SC_SUFFRAGIUM: /* サフラギム */
+ case SC_BENEDICTIO: /* 聖体 */
+ case SC_MAGNIFICAT: /* マグニフィカート */
+ case SC_AETERNA: /* エーテルナ */
+ break;
+ case SC_ENERGYCOAT: /* エナジーコート */
+ *opt3 |= 4;
+ break;
+ case SC_MAGICROD:
+ val2 = val1*20;
+ break;
+ case SC_KYRIE: /* キリエエレイソン */
+ val2 = battle_get_max_hp(bl) * (val1 * 2 + 10) / 100;/* 耐久度 */
+ val3 = (val1 / 2 + 5); /* 回数 */
+// -- moonsoul (added to undo assumptio status if target has it)
+ if(sc_data[SC_ASSUMPTIO].timer!=-1 )
+ skill_status_change_end(bl,SC_ASSUMPTIO,-1);
+ break;
+ case SC_MINDBREAKER:
+ calc_flag = 1;
+ if(tick <= 0) tick = 1000; /* (オートバーサーク) */
+ case SC_GLORIA: /* グロリア */
+ calc_flag = 1;
+ break;
+ case SC_LOUD: /* ラウドボイス */
+ calc_flag = 1;
+ break;
+ case SC_TRICKDEAD: /* 死んだふり */
+ break;
+ case SC_QUAGMIRE: /* クァグマイア */
+ calc_flag = 1;
+ if(sc_data[SC_CONCENTRATE].timer!=-1 ) /* 集中力向上解除 */
+ skill_status_change_end(bl,SC_CONCENTRATE,-1);
+ if(sc_data[SC_INCREASEAGI].timer!=-1 ) /* 速度上昇解除 */
+ skill_status_change_end(bl,SC_INCREASEAGI,-1);
+ if(sc_data[SC_TWOHANDQUICKEN].timer!=-1 )
+ skill_status_change_end(bl,SC_TWOHANDQUICKEN,-1);
+ if(sc_data[SC_SPEARSQUICKEN].timer!=-1 )
+ skill_status_change_end(bl,SC_SPEARSQUICKEN,-1);
+ if(sc_data[SC_ADRENALINE].timer!=-1 )
+ skill_status_change_end(bl,SC_ADRENALINE,-1);
+ if(sc_data[SC_LOUD].timer!=-1 )
+ skill_status_change_end(bl,SC_LOUD,-1);
+ if(sc_data[SC_TRUESIGHT].timer!=-1 ) /* トゥルーサイト */
+ skill_status_change_end(bl,SC_TRUESIGHT,-1);
+ if(sc_data[SC_WINDWALK].timer!=-1 ) /* ウインドウォーク */
+ skill_status_change_end(bl,SC_WINDWALK,-1);
+ if(sc_data[SC_CARTBOOST].timer!=-1 ) /* カートブースト */
+ skill_status_change_end(bl,SC_CARTBOOST,-1);
+ break;
+ case SC_FLAMELAUNCHER: /* フレームランチャー */
+ skill_encchant_eremental_end(bl,SC_FLAMELAUNCHER);
+ break;
+ case SC_FROSTWEAPON: /* フロストウェポン */
+ skill_encchant_eremental_end(bl,SC_FROSTWEAPON);
+ break;
+ case SC_LIGHTNINGLOADER: /* ライトニングローダー */
+ skill_encchant_eremental_end(bl,SC_LIGHTNINGLOADER);
+ break;
+ case SC_SEISMICWEAPON: /* サイズミックウェポン */
+ skill_encchant_eremental_end(bl,SC_SEISMICWEAPON);
+ break;
+ case SC_DEVOTION: /* ディボーション */
+ calc_flag = 1;
+ break;
+ case SC_PROVIDENCE: /* プロヴィデンス */
+ calc_flag = 1;
+ val2=val1*5;
+ break;
+ case SC_REFLECTSHIELD:
+ val2=10+val1*3;
+ break;
+ case SC_STRIPWEAPON:
+ case SC_STRIPSHIELD:
+ case SC_STRIPARMOR:
+ case SC_STRIPHELM:
+ case SC_CP_WEAPON:
+ case SC_CP_SHIELD:
+ case SC_CP_ARMOR:
+ case SC_CP_HELM:
+ break;
+
+ case SC_AUTOSPELL: /* オートスペル */
+ val4 = 5 + val1*2;
+ break;
+
+ case SC_VOLCANO:
+ calc_flag = 1;
+ val3 = val1*10;
+ val4 = val1>=5?20: (val1==4?19: (val1==3?17: ( val1==2?14:10 ) ) );
+ break;
+ case SC_DELUGE:
+ calc_flag = 1;
+ val3 = val1>=5?15: (val1==4?14: (val1==3?12: ( val1==2?9:5 ) ) );
+ val4 = val1>=5?20: (val1==4?19: (val1==3?17: ( val1==2?14:10 ) ) );
+ break;
+ case SC_VIOLENTGALE:
+ calc_flag = 1;
+ val3 = val1*3;
+ val4 = val1>=5?20: (val1==4?19: (val1==3?17: ( val1==2?14:10 ) ) );
+ break;
+
+ case SC_SPEARSQUICKEN: /* スピアクイッケン */
+ calc_flag = 1;
+ val2 = 20+val1;
+ *opt3 |= 1;
+ break;
+ case SC_COMBO:
+ break;
+ case SC_BLADESTOP_WAIT: /* 白刃取り(待ち) */
+ break;
+ case SC_BLADESTOP: /* 白刃取り */
+ if(val2==2) clif_bladestop((struct block_list *)val3,(struct block_list *)val4,1);
+ *opt3 |= 32;
+ break;
+
+ case SC_LULLABY: /* 子守唄 */
+ val2 = 11;
+ break;
+ case SC_RICHMANKIM:
+ break;
+ case SC_ETERNALCHAOS: /* エターナルカオス */
+ calc_flag = 1;
+ break;
+ case SC_DRUMBATTLE: /* 戦太鼓の響き */
+ calc_flag = 1;
+ val2 = (val1+1)*25;
+ val3 = (val1+1)*2;
+ break;
+ case SC_NIBELUNGEN: /* ニーベルングの指輪 */
+ calc_flag = 1;
+ val2 = (val1+2)*50;
+ val3 = (val1+2)*25;
+ break;
+ case SC_ROKISWEIL: /* ロキの叫び */
+ break;
+ case SC_INTOABYSS: /* 深淵の中に */
+ break;
+ case SC_SIEGFRIED: /* 不死身のジークフリード */
+ calc_flag = 1;
+ val2 = 40 + val1*5;
+ val3 = val1*10;
+ break;
+ case SC_DISSONANCE: /* 不協和音 */
+ val2 = 10;
+ break;
+ case SC_WHISTLE: /* 口笛 */
+ calc_flag = 1;
+ break;
+ case SC_ASSNCROS: /* 夕陽のアサシンクロス */
+ calc_flag = 1;
+ break;
+ case SC_POEMBRAGI: /* ブラギの詩 */
+ break;
+ case SC_APPLEIDUN: /* イドゥンの林檎 */
+ calc_flag = 1;
+ break;
+ case SC_UGLYDANCE: /* 自分勝手なダンス */
+ val2 = 10;
+ break;
+ case SC_HUMMING: /* ハミング */
+ calc_flag = 1;
+ break;
+ case SC_DONTFORGETME: /* 私を忘れないで */
+ calc_flag = 1;
+ if(sc_data[SC_INCREASEAGI].timer!=-1 ) /* 速度上昇解除 */
+ skill_status_change_end(bl,SC_INCREASEAGI,-1);
+ if(sc_data[SC_TWOHANDQUICKEN].timer!=-1 )
+ skill_status_change_end(bl,SC_TWOHANDQUICKEN,-1);
+ if(sc_data[SC_SPEARSQUICKEN].timer!=-1 )
+ skill_status_change_end(bl,SC_SPEARSQUICKEN,-1);
+ if(sc_data[SC_ADRENALINE].timer!=-1 )
+ skill_status_change_end(bl,SC_ADRENALINE,-1);
+ if(sc_data[SC_ASSNCROS].timer!=-1 )
+ skill_status_change_end(bl,SC_ASSNCROS,-1);
+ if(sc_data[SC_TRUESIGHT].timer!=-1 ) /* トゥルーサイト */
+ skill_status_change_end(bl,SC_TRUESIGHT,-1);
+ if(sc_data[SC_WINDWALK].timer!=-1 ) /* ウインドウォーク */
+ skill_status_change_end(bl,SC_WINDWALK,-1);
+ if(sc_data[SC_CARTBOOST].timer!=-1 ) /* カートブースト */
+ skill_status_change_end(bl,SC_CARTBOOST,-1);
+ break;
+ case SC_FORTUNE: /* 幸運のキス */
+ calc_flag = 1;
+ break;
+ case SC_SERVICE4U: /* サービスフォーユー */
+ calc_flag = 1;
+ break;
+ case SC_DANCING: /* ダンス/演奏中 */
+ calc_flag = 1;
+ val3= tick / 1000;
+ tick = 1000;
+ break;
+
+ case SC_EXPLOSIONSPIRITS: // 爆裂波動
+ calc_flag = 1;
+ val2 = 75 + 25*val1;
+ *opt3 |= 8;
+ break;
+ case SC_STEELBODY: // 金剛
+ calc_flag = 1;
+ *opt3 |= 16;
+ break;
+ case SC_EXTREMITYFIST: /* 阿修羅覇凰拳 */
+ break;
+ case SC_AUTOCOUNTER:
+ val3 = val4 = 0;
+ break;
+
+ case SC_SPEEDPOTION0: /* 増速ポーション */
+ case SC_SPEEDPOTION1:
+ case SC_SPEEDPOTION2:
+ calc_flag = 1;
+ tick = 1000 * tick;
+ val2 = 5*(2+type-SC_SPEEDPOTION0);
+ break;
+
+ /* atk & matk potions [Valaris] */
+ case SC_ATKPOT:
+ case SC_MATKPOT:
+ calc_flag = 1;
+ tick = 1000 * tick;
+ break;
+ case SC_WEDDING: //結婚用(結婚衣裳になって歩くのが遅いとか)
+ {
+ time_t timer;
+
+ calc_flag = 1;
+ tick = 10000;
+ if(!val2)
+ val2 = time(&timer);
+ }
+ break;
+ case SC_NOCHAT: //チャット禁止状態
+ {
+ time_t timer;
+
+ if(!battle_config.muting_players)
+ break;
+
+ tick = 60000;
+ if(!val2)
+ val2 = time(&timer);
+ updateflag = SP_MANNER;
+ }
+ break;
+ case SC_SELFDESTRUCTION: //自爆
+ clif_skillcasting(bl,bl->id, bl->id,0,0,331,skill_get_time(val2,val1));
+ val3 = tick / 1000;
+ tick = 1000;
+ break;
+
+ /* option1 */
+ case SC_STONE: /* 石化 */
+ if(!(flag&2)) {
+ int sc_def = battle_get_mdef(bl)*200;
+ tick = tick - sc_def;
+ }
+ val3 = tick/1000;
+ if(val3 < 1) val3 = 1;
+ tick = 5000;
+ val2 = 1;
+ break;
+ case SC_SLEEP: /* 睡眠 */
+ if(!(flag&2)) {
+// int sc_def = 100 - (battle_get_int(bl) + battle_get_luk(bl)/3);
+// tick = tick * sc_def / 100;
+// if(tick < 1000) tick = 1000;
+ tick = 30000;//睡眠はステータス耐性に関わらず30秒
+ }
+ break;
+ case SC_FREEZE: /* 凍結 */
+ if(!(flag&2)) {
+ int sc_def = 100 - battle_get_mdef(bl);
+ tick = tick * sc_def / 100;
+ }
+ break;
+ case SC_STAN: /* スタン(val2にミリ秒セット) */
+ if(!(flag&2)) {
+ int sc_def = 100 - (battle_get_vit(bl) + battle_get_luk(bl)/3);
+ tick = tick * sc_def / 100;
+ }
+ break;
+
+ /* option2 */
+ case SC_POISON: /* 毒 */
+ calc_flag = 1;
+ if(!(flag&2)) {
+ int sc_def = 100 - (battle_get_vit(bl) + battle_get_luk(bl)/5);
+ tick = tick * sc_def / 100;
+ }
+ val3 = tick/1000;
+ if(val3 < 1) val3 = 1;
+ tick = 1000;
+ break;
+ case SC_SILENCE: /* 沈黙(レックスデビーナ) */
+ if(!(flag&2)) {
+ int sc_def = 100 - battle_get_vit(bl);
+ tick = tick * sc_def / 100;
+ }
+ break;
+ case SC_BLIND: /* 暗黒 */
+ calc_flag = 1;
+ if(!(flag&2)) {
+ int sc_def = battle_get_lv(bl)/10 + battle_get_int(bl)/15;
+ tick = 30000 - sc_def;
+ }
+ break;
+ case SC_CURSE:
+ calc_flag = 1;
+ if(!(flag&2)) {
+ int sc_def = 100 - battle_get_vit(bl);
+ tick = tick * sc_def / 100;
+ }
+ break;
+
+ /* option */
+ case SC_HIDING: /* ハイディング */
+ calc_flag = 1;
+ if(bl->type == BL_PC) {
+ val2 = tick / 1000; /* 持続時間 */
+ tick = 1000;
+ }
+ break;
+ case SC_CHASEWALK:
+ case SC_CLOAKING: /* クローキング */
+ calc_flag = 1; // [Celest]
+ if(bl->type == BL_PC)
+ val2 = tick;
+ else
+ tick = 5000*val1;
+ break;
+ case SC_SIGHT: /* サイト/ルアフ */
+ case SC_RUWACH:
+ val2 = tick/250;
+ tick = 10;
+ break;
+
+ /* セーフティウォール、ニューマ */
+ case SC_SAFETYWALL: case SC_PNEUMA:
+ tick=((struct skill_unit *)val2)->group->limit;
+ break;
+
+ /* アンクル */
+ case SC_ANKLE:
+ break;
+
+ /* ウォーターボール */
+ case SC_WATERBALL:
+ tick=150;
+ if(val1>5) //レベルが5以上の場合は25発に制限(1発目はすでに打ってるので-1)
+ val3=5*5-1;
+ else
+ val3= (val1|1)*(val1|1)-1;
+ break;
+
+ /* スキルじゃない/時間に関係しない */
+ case SC_RIDING:
+ calc_flag = 1;
+ tick = 600*1000;
+ break;
+ case SC_FALCON:
+ case SC_WEIGHT50:
+ case SC_WEIGHT90:
+ case SC_BROKNWEAPON:
+ case SC_BROKNARMOR:
+ tick=600*1000;
+ break;
+
+ case SC_AUTOGUARD:
+ {
+ int i,t;
+ for(i=val2=0;i<val1;i++) {
+ t = 5-(i>>1);
+ val2 += (t < 0)? 1:t;
+ }
+ }
+ break;
+
+ case SC_DEFENDER:
+ calc_flag = 1;
+ val2 = 5 + val1*15;
+ break;
+
+ case SC_KEEPING:
+ case SC_BARRIER:
+ case SC_HALLUCINATION:
+ break;
+ case SC_CONCENTRATION: /* コンセントレーション */
+ *opt3 |= 1;
+ calc_flag = 1;
+ break;
+ case SC_TENSIONRELAX: /* テンションリラックス */
+ calc_flag = 1;
+ if(bl->type == BL_PC) {
+ tick = 10000;
+ }
+ break;
+ case SC_AURABLADE: /* オーラブレード */
+ case SC_PARRYING: /* パリイング */
+// case SC_ASSUMPTIO: /* */
+ case SC_HEADCRUSH: /* ヘッドクラッシュ */
+ case SC_JOINTBEAT: /* ジョイントビート */
+// case SC_MARIONETTE: /* マリオネットコントロール */
+
+ //とりあえず手抜き
+ break;
+
+// -- moonsoul (for new upper class related skill status effects)
+/*
+ case SC_AURABLADE:
+ val2 = val1*10;
+ break;
+ case SC_PARRYING:
+ val2=val1*3;
+ break;
+ case SC_CONCENTRATION:
+ calc_flag=1;
+ val2=val1*10;
+ val3=val1*5;
+ break;
+ case SC_TENSIONRELAX:
+// val2 = 10;
+// val3 = 15;
+ break;
+ case SC_BERSERK:
+ calc_flag=1;
+ break;
+ case SC_ASSUMPTIO:
+ if(sc_data[SC_KYRIE].timer!=-1 )
+ skill_status_change_end(bl,SC_KYRIE,-1);
+ break;
+*/
+ case SC_WINDWALK: /* ウインドウォーク */
+ calc_flag = 1;
+ val2 = (val1 / 2); //Flee上昇率
+ break;
+ case SC_BERSERK: /* バーサーク */
+ if(sd){
+ sd->status.sp = 0;
+ clif_updatestatus(sd,SP_SP);
+ clif_status_change(bl,SC_INCREASEAGI,1); /* アイコン表示 */
+ }
+ *opt3 |= 128;
+ tick = 1000;
+ calc_flag = 1;
+ break;
+ case SC_ASSUMPTIO: /* アスムプティオ */
+ *opt3 |= 2048;
+ break;
+ case SC_MARIONETTE: /* マリオネットコントロール */
+ *opt3 |= 1024;
+ break;
+ case SC_MELTDOWN: /* メルトダウン */
+ case SC_CARTBOOST: /* カートブースト */
+ case SC_TRUESIGHT: /* トゥルーサイト */
+ case SC_SPIDERWEB: /* スパイダーウェッブ */
+ case SC_MAGICPOWER: /* 魔法力増幅 */
+ calc_flag = 1;
+ break;
+ case SC_REJECTSWORD: /* リジェクトソード */
+ val2 = 3; //3回攻撃を跳ね返す
+ break;
+ case SC_MEMORIZE: /* メモライズ */
+ val2 = 3; //3回詠唱を1/3にする
+ break;
+ case SC_GRAFFITI: /* グラフィティ */
+ {
+ struct skill_unit_group *sg = skill_unitsetting(bl,RG_GRAFFITI,val1,val2,val3,0);
+ if(sg)
+ val4 = (int)sg;
+ }
+ break;
+ case SC_SPLASHER: /* ベナムスプラッシャー */
+ break;
+ default:
+ if(battle_config.error_log)
+ printf("UnknownStatusChange [%d]\n", type);
+ return 0;
+ }
+
+ if(bl->type==BL_PC && type<SC_SENDMAX)
+ clif_status_change(bl,type,1); /* アイコン表示 */
+
+ /* optionの変更 */
+ switch(type){
+ case SC_STONE:
+ case SC_FREEZE:
+ case SC_STAN:
+ case SC_SLEEP:
+ battle_stopattack(bl); /* 攻撃停止 */
+ skill_stop_dancing(bl,0); /* 演奏/ダンスの中断 */
+ { /* 同時に掛からないステータス異常を解除 */
+ int i;
+ for(i = SC_STONE; i <= SC_SLEEP; i++){
+ if(sc_data[i].timer != -1){
+ (*sc_count)--;
+ delete_timer(sc_data[i].timer, skill_status_change_timer);
+ sc_data[i].timer = -1;
+ }
+ }
+ }
+ if(type == SC_STONE)
+ *opt1 = 6;
+ else
+ *opt1 = type - SC_STONE + 1;
+ opt_flag = 1;
+ break;
+ case SC_POISON:
+ case SC_CURSE:
+ case SC_SILENCE:
+ case SC_BLIND:
+ *opt2 |= 1<<(type-SC_POISON);
+ opt_flag = 1;
+ break;
+ case SC_SIGNUMCRUCIS:
+ *opt2 |= 0x40;
+ opt_flag = 1;
+ break;
+ case SC_HIDING:
+ case SC_CLOAKING:
+ battle_stopattack(bl); /* 攻撃停止 */
+ *option |= ((type==SC_HIDING)?2:4);
+ opt_flag =1 ;
+ break;
+ case SC_CHASEWALK:
+ battle_stopattack(bl); /* 攻撃停止 */
+ *option |= 16388;
+ opt_flag =1 ;
+ break;
+ case SC_SIGHT:
+ *option |= 1;
+ opt_flag = 1;
+ break;
+ case SC_RUWACH:
+ *option |= 8192;
+ opt_flag = 1;
+ break;
+ case SC_WEDDING:
+ *option |= 4096;
+ opt_flag = 1;
+ }
+
+ if(opt_flag) /* optionの変更 */
+ clif_changeoption(bl);
+
+ (*sc_count)++; /* ステータス異常の数 */
+
+ sc_data[type].val1 = val1;
+ sc_data[type].val2 = val2;
+ sc_data[type].val3 = val3;
+ sc_data[type].val4 = val4;
+ /* タイマー設定 */
+ sc_data[type].timer = add_timer(
+ gettick() + tick, skill_status_change_timer, bl->id, type);
+
+ if(bl->type==BL_PC && calc_flag)
+ pc_calcstatus(sd,0); /* ステータス再計算 */
+
+ if(bl->type==BL_PC && updateflag)
+ clif_updatestatus(sd,updateflag); /* ステータスをクライアントに送る */
+
+ return 0;
+}
+/*==========================================
+ * ステータス異常全解除
+ *------------------------------------------
+ */
+int skill_status_change_clear(struct block_list *bl, int type)
+{
+ struct status_change* sc_data;
+ short *sc_count, *option, *opt1, *opt2, *opt3;
+ int i;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, sc_data = battle_get_sc_data(bl));
+ nullpo_retr(0, sc_count = battle_get_sc_count(bl));
+ nullpo_retr(0, option = battle_get_option(bl));
+ nullpo_retr(0, opt1 = battle_get_opt1(bl));
+ nullpo_retr(0, opt2 = battle_get_opt2(bl));
+ nullpo_retr(0, opt3 = battle_get_opt3(bl));
+
+ if (*sc_count == 0)
+ return 0;
+ for(i = 0; i < MAX_STATUSCHANGE; i++){
+ if(sc_data[i].timer != -1){ /* 異常があるならタイマーを削除する */
+/*
+ delete_timer(sc_data[i].timer, skill_status_change_timer);
+ sc_data[i].timer = -1;
+
+ if (!type && i < SC_SENDMAX)
+ clif_status_change(bl, i, 0);
+*/
+
+ skill_status_change_end(bl, i, -1);
+ }
+ }
+ *sc_count = 0;
+ *opt1 = 0;
+ *opt2 = 0;
+ *opt3 = 0;
+ *option &= OPTION_MASK;
+
+ if (night_flag == 1 && type == BL_PC) // by [Yor]
+ *opt2 |= STATE_BLIND;
+
+ if(!type || type&2)
+ clif_changeoption(bl);
+
+ return 0;
+}
+
+/* クローキング検査(周りに移動不可能地帯があるか) */
+int skill_check_cloaking(struct block_list *bl)
+{
+ struct map_session_data *sd=NULL;
+ static int dx[]={-1, 0, 1,-1, 1,-1, 0, 1};
+ static int dy[]={-1,-1,-1, 0, 0, 1, 1, 1};
+ int end=1,i;
+
+ nullpo_retr(0, bl);
+ sd=(struct map_session_data *)bl; //missing sd [Found by Celest, commited by Aria]
+
+ if(pc_checkskill(sd,AS_CLOAKING)>2)
+ return 0;
+ if(bl->type == BL_PC && battle_config.pc_cloak_check_type&1)
+ return 0;
+ if(bl->type == BL_MOB && battle_config.monster_cloak_check_type&1)
+ return 0;
+ for(i=0;i<sizeof(dx)/sizeof(dx[0]);i++){
+ int c=map_getcell(bl->m,bl->x+dx[i],bl->y+dy[i]);
+ if(c==1 || c==5) end=0;
+ }
+ if(end){
+ skill_status_change_end(bl, SC_CLOAKING, -1);
+ *battle_get_option(bl)&=~4; /* 念のための処理 */
+ }
+ return end;
+}
+
+int skill_type_cloaking(struct block_list *bl)
+{
+ static int dx[]={-1, 0, 1,-1, 1,-1, 0, 1};
+ static int dy[]={-1,-1,-1, 0, 0, 1, 1, 1};
+ int end=1,i;
+
+ nullpo_retr(0, bl);
+ if(bl->type == BL_PC && battle_config.pc_cloak_check_type&1)
+ return 0;
+ if(bl->type == BL_MOB && battle_config.monster_cloak_check_type&1)
+ return 0;
+ for(i=0; i<sizeof(dx)/sizeof(dx[0]); i++)
+ {
+ int c=map_getcell(bl->m,bl->x+dx[i],bl->y+dy[i]);
+ if(c==1 || c==5) end=0;
+ }
+ return end;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * スキルユニット
+ *----------------------------------------------------------------------------
+ */
+
+/*==========================================
+ * 演奏/ダンススキルかどうか判定
+ * 引数 スキルID
+ * 戻り ダンスじゃない=0 合奏=2 それ以外のダンス=1
+ *------------------------------------------
+ */
+int skill_is_danceskill(int id)
+{
+ int i;
+ switch(id){
+ case BD_LULLABY: /* 子守歌 */
+ case BD_RICHMANKIM: /* ニヨルドの宴 */
+ case BD_ETERNALCHAOS: /* 永遠の混沌 */
+ case BD_DRUMBATTLEFIELD: /* 戦太鼓の響き */
+ case BD_RINGNIBELUNGEN: /* ニーベルングの指輪 */
+ case BD_ROKISWEIL: /* ロキの叫び */
+ case BD_INTOABYSS: /* 深淵の中に */
+ case BD_SIEGFRIED: /* 不死身のジークフリード */
+ case BD_RAGNAROK: /* 神々の黄昏 */
+ case CG_MOONLIT: /* 月明りの泉に落ちる花びら */
+ i=2;
+ break;
+ case BA_DISSONANCE: /* 不協和音 */
+ case BA_FROSTJOKE: /* 寒いジョーク */
+ case BA_WHISTLE: /* 口笛 */
+ case BA_ASSASSINCROSS: /* 夕陽のアサシンクロス */
+ case BA_POEMBRAGI: /* ブラギの詩 */
+ case BA_APPLEIDUN: /* イドゥンの林檎 */
+ case DC_UGLYDANCE: /* 自分勝手なダンス */
+ case DC_SCREAM: /* スクリーム */
+ case DC_HUMMING: /* ハミング */
+ case DC_DONTFORGETME: /* 私を忘れないで… */
+ case DC_FORTUNEKISS: /* 幸運のキス */
+ case DC_SERVICEFORYOU: /* サービスフォーユー */
+ i=1;
+ break;
+ default:
+ i=0;
+ }
+ return i;
+}
+
+/*==========================================
+ * 演奏/ダンスをやめる
+ * flag 1で合奏中なら相方にユニットを任せる
+ *
+ *------------------------------------------
+ */
+void skill_stop_dancing(struct block_list *src, int flag)
+{
+ struct status_change* sc_data;
+ struct skill_unit_group* group;
+
+ nullpo_retv(src);
+
+ sc_data=battle_get_sc_data(src);
+ if(sc_data && sc_data[SC_DANCING].timer==-1)
+ return;
+ group=(struct skill_unit_group *)sc_data[SC_DANCING].val2; //ダンスのスキルユニットIDはval2に入ってる
+ if(group && src->type==BL_PC && sc_data && sc_data[SC_DANCING].val4){ //合奏中断
+ struct map_session_data* dsd=map_id2sd(sc_data[SC_DANCING].val4); //相方のsd取得
+ if(flag){ //ログアウトなど片方が落ちても演奏が継続される
+ if(dsd && src->id == group->src_id){ //グループを持ってるPCが落ちる
+ group->src_id=sc_data[SC_DANCING].val4; //相方にグループを任せる
+ if(flag&1) //ログアウト
+ dsd->sc_data[SC_DANCING].val4=0; //相方の相方を0にして合奏終了→通常のダンス状態
+ if(flag&2) //ハエ飛びなど
+ return; //合奏もダンス状態も終了させない&スキルユニットは置いてけぼり
+ }else if(dsd && dsd->bl.id == group->src_id){ //相方がグループを持っているPCが落ちる(自分はグループを持っていない)
+ if(flag&1) //ログアウト
+ dsd->sc_data[SC_DANCING].val4=0; //相方の相方を0にして合奏終了→通常のダンス状態
+ if(flag&2) //ハエ飛びなど
+ return; //合奏もダンス状態も終了させない&スキルユニットは置いてけぼり
+ }
+ skill_status_change_end(src,SC_DANCING,-1);//自分のステータスを終了させる
+ //そしてグループは消さない&消さないのでステータス計算もいらない?
+ return;
+ }else{
+ if(dsd && src->id == group->src_id){ //グループを持ってるPCが止める
+ skill_status_change_end((struct block_list *)dsd,SC_DANCING,-1);//相手のステータスを終了させる
+ }
+ if(dsd && dsd->bl.id == group->src_id){ //相方がグループを持っているPCが止める(自分はグループを持っていない)
+ skill_status_change_end(src,SC_DANCING,-1);//自分のステータスを終了させる
+ }
+ }
+ }
+ if(flag&2 && group && src->type==BL_PC){ //ハエで飛んだときとかはユニットも飛ぶ
+ struct map_session_data *sd = (struct map_session_data *)src;
+ skill_unit_move_unit_group(group, sd->bl.m,(sd->to_x - sd->bl.x),(sd->to_y - sd->bl.y));
+ return;
+ }
+ skill_delunitgroup(group);
+ if(src->type==BL_PC)
+ pc_calcstatus((struct map_session_data *)src,0);
+}
+
+/*==========================================
+ * スキルユニット初期化
+ *------------------------------------------
+ */
+struct skill_unit *skill_initunit(struct skill_unit_group *group,int idx,int x,int y)
+{
+ struct skill_unit *unit;
+
+ nullpo_retr(NULL, group);
+ nullpo_retr(NULL, unit=&group->unit[idx]);
+
+ if(!unit->alive)
+ group->alive_count++;
+
+ unit->bl.id=map_addobject(&unit->bl);
+ unit->bl.type=BL_SKILL;
+ unit->bl.m=group->map;
+ unit->bl.x=x;
+ unit->bl.y=y;
+ unit->group=group;
+ unit->val1=unit->val2=0;
+ unit->alive=1;
+
+ map_addblock(&unit->bl);
+ clif_skill_setunit(unit);
+ return unit;
+}
+
+int skill_unit_timer_sub_ondelete( struct block_list *bl, va_list ap );
+/*==========================================
+ * スキルユニット削除
+ *------------------------------------------
+ */
+int skill_delunit(struct skill_unit *unit)
+{
+ struct skill_unit_group *group;
+ int range;
+
+ nullpo_retr(0, unit);
+ if(!unit->alive)
+ return 0;
+ nullpo_retr(0, group=unit->group);
+
+ /* onlimitイベント呼び出し */
+ skill_unit_onlimit( unit,gettick() );
+
+ /* ondeleteイベント呼び出し */
+ range=group->range;
+ map_foreachinarea( skill_unit_timer_sub_ondelete, unit->bl.m,
+ unit->bl.x-range,unit->bl.y-range,unit->bl.x+range,unit->bl.y+range,0,
+ &unit->bl,gettick() );
+
+ clif_skill_delunit(unit);
+
+ unit->group=NULL;
+ unit->alive=0;
+ map_delobjectnofree(unit->bl.id);
+ if(group->alive_count>0 && (--group->alive_count)<=0)
+ skill_delunitgroup(group);
+
+ return 0;
+}
+/*==========================================
+ * スキルユニットグループ初期化
+ *------------------------------------------
+ */
+static int skill_unit_group_newid=10;
+struct skill_unit_group *skill_initunitgroup(struct block_list *src,
+ int count,int skillid,int skilllv,int unit_id)
+{
+ int i;
+ struct skill_unit_group *group=NULL, *list=NULL;
+ int maxsug=0;
+
+ nullpo_retr(NULL, src);
+
+ if(src->type==BL_PC){
+ list=((struct map_session_data *)src)->skillunit;
+ maxsug=MAX_SKILLUNITGROUP;
+ }else if(src->type==BL_MOB){
+ list=((struct mob_data *)src)->skillunit;
+ maxsug=MAX_MOBSKILLUNITGROUP;
+ }else if(src->type==BL_PET){
+ list=((struct pet_data *)src)->skillunit;
+ maxsug=MAX_MOBSKILLUNITGROUP;
+ }
+ if(list){
+ for(i=0;i<maxsug;i++) /* 空いているもの検索 */
+ if(list[i].group_id==0){
+ group=&list[i];
+ break;
+ }
+
+ if(group==NULL){ /* 空いてないので古いもの検索 */
+ int j=0;
+ unsigned maxdiff=0,x,tick=gettick();
+ for(i=0;i<maxsug;i++)
+ if((x=DIFF_TICK(tick,list[i].tick))>maxdiff){
+ maxdiff=x;
+ j=i;
+ }
+ skill_delunitgroup(&list[j]);
+ group=&list[j];
+ }
+ }
+
+ if(group==NULL){
+ printf("skill_initunitgroup: error unit group !\n");
+ exit(1);
+ }
+
+ group->src_id=src->id;
+ group->party_id=battle_get_party_id(src);
+ group->guild_id=battle_get_guild_id(src);
+ group->group_id=skill_unit_group_newid++;
+ if(skill_unit_group_newid<=0)
+ skill_unit_group_newid=10;
+ group->unit=(struct skill_unit *)aCalloc(count,sizeof(struct skill_unit));
+ group->unit_count=count;
+ group->val1=group->val2=0;
+ group->skill_id=skillid;
+ group->skill_lv=skilllv;
+ group->unit_id=unit_id;
+ group->map=src->m;
+ group->range=0;
+ group->limit=10000;
+ group->interval=1000;
+ group->tick=gettick();
+ group->valstr=NULL;
+
+ if( skill_is_danceskill(skillid) ){
+ struct map_session_data *sd = NULL;
+ if(src->type==BL_PC && (sd=(struct map_session_data *)src) ){
+ sd->skillid_dance=skillid;
+ sd->skilllv_dance=skilllv;
+ }
+ skill_status_change_start(src,SC_DANCING,skillid,(int)group,0,0,skill_get_time(skillid,skilllv)+1000,0);
+ switch(skillid){ //合奏スキルは相方をダンス状態にする
+ case BD_LULLABY: /* 子守歌 */
+ case BD_RICHMANKIM: /* ニヨルドの宴 */
+ case BD_ETERNALCHAOS: /* 永遠の混沌 */
+ case BD_DRUMBATTLEFIELD: /* 戦太鼓の響き */
+ case BD_RINGNIBELUNGEN: /* ニーベルングの指輪 */
+ case BD_ROKISWEIL: /* ロキの叫び */
+ case BD_INTOABYSS: /* 深淵の中に */
+ case BD_SIEGFRIED: /* 不死身のジークフリード */
+ case BD_RAGNAROK: /* 神々の黄昏 */
+ case CG_MOONLIT: /* 月明りの泉に落ちる花びら */
+ {
+ int range=1;
+ int c=0;
+ if(sd){
+ map_foreachinarea(skill_check_condition_use_sub,sd->bl.m,
+ sd->bl.x-range,sd->bl.y-range,
+ sd->bl.x+range,sd->bl.y+range,BL_PC,&sd->bl,&c);
+ }
+ }
+ }
+ }
+ return group;
+}
+
+/*==========================================
+ * スキルユニットグループ削除
+ *------------------------------------------
+ */
+int skill_delunitgroup(struct skill_unit_group *group)
+{
+ struct block_list *src;
+ int i;
+
+ nullpo_retr(0, group);
+ if(group->unit_count<=0)
+ return 0;
+
+ src=map_id2bl(group->src_id);
+ if( skill_is_danceskill(group->skill_id) ){ //ダンススキルはダンス状態を解除する
+ if(src)
+ skill_status_change_end(src,SC_DANCING,-1);
+ }
+
+ group->alive_count=0;
+ if(group->unit!=NULL){
+ for(i=0;i<group->unit_count;i++)
+ if(group->unit[i].alive)
+ skill_delunit(&group->unit[i]);
+ }
+ if(group->valstr!=NULL){
+ map_freeblock(group->valstr);
+ group->valstr=NULL;
+ }
+
+ map_freeblock(group->unit); /* free()の替わり */
+ group->unit=NULL;
+ group->src_id=0;
+ group->group_id=0;
+ group->unit_count=0;
+ return 0;
+}
+
+/*==========================================
+ * スキルユニットグループ全削除
+ *------------------------------------------
+ */
+int skill_clear_unitgroup(struct block_list *src)
+{
+ struct skill_unit_group *group=NULL;
+ int maxsug=0;
+
+ nullpo_retr(0, src);
+
+ if(src->type==BL_PC){
+ group=((struct map_session_data *)src)->skillunit;
+ maxsug=MAX_SKILLUNITGROUP;
+ }else if(src->type==BL_MOB){
+ group=((struct mob_data *)src)->skillunit;
+ maxsug=MAX_MOBSKILLUNITGROUP;
+ }else if(src->type==BL_PET){ // [Valaris]
+ group=((struct pet_data *)src)->skillunit;
+ maxsug=MAX_MOBSKILLUNITGROUP;
+ }
+ if(group){
+ int i;
+ for(i=0;i<maxsug;i++)
+ if(group[i].group_id>0 && group[i].src_id == src->id)
+ skill_delunitgroup(&group[i]);
+ }
+ return 0;
+}
+
+/*==========================================
+ * スキルユニットグループの被影響tick検索
+ *------------------------------------------
+ */
+struct skill_unit_group_tickset *skill_unitgrouptickset_search(
+ struct block_list *bl,int group_id)
+{
+ int i,j=0,k,s=group_id%MAX_SKILLUNITGROUPTICKSET;
+ struct skill_unit_group_tickset *set=NULL;
+
+ nullpo_retr(0, bl);
+
+ if(bl->type==BL_PC){
+ set=((struct map_session_data *)bl)->skillunittick;
+ }else{
+ set=((struct mob_data *)bl)->skillunittick;
+ }
+ if(set==NULL)
+ return 0;
+ for(i=0;i<MAX_SKILLUNITGROUPTICKSET;i++)
+ if( set[(k=(i+s)%MAX_SKILLUNITGROUPTICKSET)].group_id == group_id )
+ return &set[k];
+ else if( set[k].group_id==0 )
+ j=k;
+
+ return &set[j];
+}
+
+/*==========================================
+ * スキルユニットグループの被影響tick削除
+ *------------------------------------------
+ */
+int skill_unitgrouptickset_delete(struct block_list *bl,int group_id)
+{
+ int i,s=group_id%MAX_SKILLUNITGROUPTICKSET;
+ struct skill_unit_group_tickset *set=NULL,*ts;
+
+ nullpo_retr(0, bl);
+
+ if(bl->type==BL_PC){
+ set=((struct map_session_data *)bl)->skillunittick;
+ }else{
+ set=((struct mob_data *)bl)->skillunittick;
+ }
+
+ if(set!=NULL){
+
+ for(i=0;i<MAX_SKILLUNITGROUPTICKSET;i++)
+ if( (ts=&set[(i+s)%MAX_SKILLUNITGROUPTICKSET])->group_id == group_id )
+ ts->group_id=0;
+
+ }
+ return 0;
+}
+
+/*==========================================
+ * スキルユニットタイマー発動処理用(foreachinarea)
+ *------------------------------------------
+ */
+int skill_unit_timer_sub_onplace( struct block_list *bl, va_list ap )
+{
+ struct block_list *src;
+ struct skill_unit *su;
+ unsigned int tick;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ src=va_arg(ap,struct block_list*);
+
+ tick=va_arg(ap,unsigned int);
+ su = (struct skill_unit *)src;
+
+ if( su && su->alive ) {
+ struct skill_unit_group *sg;
+ sg = su->group;
+ if(sg && battle_check_target(src,bl,sg->target_flag )>0)
+ skill_unit_onplace( su, bl, tick );
+ }
+ return 0;
+}
+
+/*==========================================
+ * スキルユニットタイマー削除処理用(foreachinarea)
+ *------------------------------------------
+ */
+int skill_unit_timer_sub_ondelete( struct block_list *bl, va_list ap )
+{
+ struct block_list *src;
+ struct skill_unit *su;
+ unsigned int tick;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ src=va_arg(ap,struct block_list*);
+
+ tick=va_arg(ap,unsigned int);
+ su = (struct skill_unit *)src;
+
+ if( su && su->alive ){
+ struct skill_unit_group *sg;
+ sg = su->group;
+ if( sg && battle_check_target(src,bl,sg->target_flag )>0 )
+ skill_unit_ondelete( su, bl, tick );
+ }
+ return 0;
+}
+
+/*==========================================
+ * スキルユニットタイマー処理用(foreachobject)
+ *------------------------------------------
+ */
+int skill_unit_timer_sub( struct block_list *bl, va_list ap )
+{
+ struct skill_unit *unit;
+ struct skill_unit_group *group;
+ int range;
+ unsigned int tick;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, unit=(struct skill_unit *)bl);
+ nullpo_retr(0, group=unit->group);
+ tick=va_arg(ap,unsigned int);
+
+ if(!unit->alive)
+ return 0;
+
+ range=(unit->range!=0)?unit->range:group->range;
+
+ /* onplaceイベント呼び出し */
+ if(unit->alive && unit->range>=0){
+ map_foreachinarea( skill_unit_timer_sub_onplace, bl->m,
+ bl->x-range,bl->y-range,bl->x+range,bl->y+range,0,
+ bl,tick);
+ if(group->unit_id == 0xaa && DIFF_TICK(tick,group->tick)>=6000*group->val2){
+ map_foreachinarea( skill_idun_heal, bl->m,
+ bl->x-range,bl->y-range,bl->x+range,bl->y+range,0,unit);
+ group->val2++;
+ }
+ }
+ /* 時間切れ削除 */
+ if(unit->alive &&
+ (DIFF_TICK(tick,group->tick)>=group->limit || DIFF_TICK(tick,group->tick)>=unit->limit) ){
+ switch(group->unit_id){
+
+
+
+
+
+
+ case 0x8f: /* ブラストマイン */
+ group->unit_id = 0x8c;
+ clif_changelook(bl,LOOK_BASE,group->unit_id);
+ group->limit=DIFF_TICK(tick+1500,group->tick);
+ unit->limit=DIFF_TICK(tick+1500,group->tick);
+ break;
+ case 0x90: /* スキッドトラップ */
+ case 0x91: /* アンクルスネア */
+ case 0x93: /* ランドマイン */
+ case 0x94: /* ショックウェーブトラップ */
+ case 0x95: /* サンドマン */
+ case 0x96: /* フラッシャー */
+ case 0x97: /* フリージングトラップ */
+ case 0x98: /* クレイモアートラップ */
+ case 0x99: /* トーキーボックス */
+ {
+ struct block_list *src=map_id2bl(group->src_id);
+ if(group->unit_id == 0x91 && group->val2);
+ else{
+ if(src && src->type==BL_PC){
+ struct item item_tmp;
+ memset(&item_tmp,0,sizeof(item_tmp));
+ item_tmp.nameid=1065;
+ item_tmp.identify=1;
+ map_addflooritem(&item_tmp,1,bl->m,bl->x,bl->y,NULL,NULL,NULL,0); // 罠返還
+ }
+ }
+ }
+ default:
+ skill_delunit(unit);
+ }
+ }
+
+ if(group->unit_id == 0x8d) {
+ unit->val1 -= 5;
+ if(unit->val1 <= 0 && unit->limit + group->tick > tick + 700)
+ unit->limit = DIFF_TICK(tick+700,group->tick);
+ }
+
+ return 0;
+}
+/*==========================================
+ * スキルユニットタイマー処理
+ *------------------------------------------
+ */
+int skill_unit_timer( int tid,unsigned int tick,int id,int data)
+{
+ map_freeblock_lock();
+
+ map_foreachobject( skill_unit_timer_sub, BL_SKILL, tick );
+
+ map_freeblock_unlock();
+
+ return 0;
+}
+
+/*==========================================
+ * スキルユニット移動時処理用(foreachinarea)
+ *------------------------------------------
+ */
+int skill_unit_out_all_sub( struct block_list *bl, va_list ap )
+{
+ struct skill_unit *unit;
+ struct skill_unit_group *group;
+ struct block_list *src;
+ int range;
+ unsigned int tick;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, src=va_arg(ap,struct block_list*));
+ nullpo_retr(0, unit=(struct skill_unit *)bl);
+ nullpo_retr(0, group=unit->group);
+
+ tick=va_arg(ap,unsigned int);
+
+ if(!unit->alive || src->prev==NULL)
+ return 0;
+
+ range=(unit->range!=0)?unit->range:group->range;
+
+ if( range<0 || battle_check_target(bl,src,group->target_flag )<=0 )
+ return 0;
+
+ if( src->x >= bl->x-range && src->x <= bl->x+range &&
+ src->y >= bl->y-range && src->y <= bl->y+range )
+ skill_unit_onout( unit, src, tick );
+
+ return 0;
+}
+
+
+/*==========================================
+ * スキルユニット移動時処理
+ *------------------------------------------
+ */
+int skill_unit_out_all( struct block_list *bl,unsigned int tick,int range)
+{
+ nullpo_retr(0, bl);
+
+ if( bl->prev==NULL )
+ return 0;
+
+ if(range<7)
+ range=7;
+ map_foreachinarea( skill_unit_out_all_sub,
+ bl->m,bl->x-range,bl->y-range,bl->x+range,bl->y+range,BL_SKILL,
+ bl,tick );
+
+ return 0;
+}
+
+/*==========================================
+ * スキルユニット移動時処理用(foreachinarea)
+ *------------------------------------------
+ */
+int skill_unit_move_sub( struct block_list *bl, va_list ap )
+{
+ struct skill_unit *unit;
+ struct skill_unit_group *group;
+ struct block_list *src;
+ int range;
+ unsigned int tick;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, unit=(struct skill_unit *)bl);
+ nullpo_retr(0, src=va_arg(ap,struct block_list*));
+
+ tick=va_arg(ap,unsigned int);
+
+ if(!unit->alive || src->prev==NULL)
+ return 0;
+
+ if((group=unit->group) == NULL)
+ return 0;
+ range=(unit->range!=0)?unit->range:group->range;
+
+ if( range<0 || battle_check_target(bl,src,group->target_flag )<=0 )
+ return 0;
+
+ if( src->x >= bl->x-range && src->x <= bl->x+range &&
+ src->y >= bl->y-range && src->y <= bl->y+range )
+ skill_unit_onplace( unit, src, tick );
+ else
+ skill_unit_onout( unit, src, tick );
+
+ return 0;
+}
+
+/*==========================================
+ * スキルユニット移動時処理
+ *------------------------------------------
+ */
+int skill_unit_move( struct block_list *bl,unsigned int tick,int range)
+{
+ nullpo_retr(0, bl);
+
+ if( bl->prev==NULL )
+ return 0;
+
+ if(range<7)
+ range=7;
+ map_foreachinarea( skill_unit_move_sub,
+ bl->m,bl->x-range,bl->y-range,bl->x+range,bl->y+range,BL_SKILL,
+ bl,tick );
+
+ return 0;
+}
+
+/*==========================================
+ * スキルユニット自体の移動時処理(foreachinarea)
+ *------------------------------------------
+ */
+int skill_unit_move_unit_group_sub( struct block_list *bl, va_list ap )
+{
+ struct skill_unit *unit;
+ struct skill_unit_group *group;
+ struct block_list *src;
+ int range;
+ unsigned int tick;
+
+ nullpo_retr(0, bl);
+ nullpo_retr(0, ap);
+ nullpo_retr(0, src=va_arg(ap,struct block_list*));
+ nullpo_retr(0, unit=(struct skill_unit *)src);
+ nullpo_retr(0, group=unit->group);
+
+ tick=va_arg(ap,unsigned int);
+
+ if(!unit->alive || bl->prev==NULL)
+ return 0;
+
+ range=(unit->range!=0)?unit->range:group->range;
+
+ if( range<0 || battle_check_target(src,bl,group->target_flag )<=0 )
+ return 0;
+ if( bl->x >= src->x-range && bl->x <= src->x+range &&
+ bl->y >= src->y-range && bl->y <= src->y+range )
+ skill_unit_onplace( unit, bl, tick );
+ else
+ skill_unit_onout( unit, bl, tick );
+ return 0;
+}
+
+/*==========================================
+ * スキルユニット自体の移動時処理
+ * 引数はグループと移動量
+ *------------------------------------------
+ */
+int skill_unit_move_unit_group( struct skill_unit_group *group, int m,int dx,int dy)
+{
+ nullpo_retr(0, group);
+
+ if( group->unit_count<=0)
+ return 0;
+
+ if(group->unit!=NULL){
+ if(!battle_config.unit_movement_type){
+ int i;
+ for(i=0;i<group->unit_count;i++){
+ struct skill_unit *unit=&group->unit[i];
+ if(unit->alive && !(m==unit->bl.m && dx==0 && dy==0)){
+ int range=unit->range;
+ map_delblock(&unit->bl);
+ unit->bl.m = m;
+ unit->bl.x += dx;
+ unit->bl.y += dy;
+ map_addblock(&unit->bl);
+ clif_skill_setunit(unit);
+ if(range>0){
+ if(range<7)
+ range=7;
+ map_foreachinarea( skill_unit_move_unit_group_sub, unit->bl.m,
+ unit->bl.x-range,unit->bl.y-range,unit->bl.x+range,unit->bl.y+range,0,
+ &unit->bl,gettick() );
+ }
+ }
+ }
+ }else{
+ int i,j, *r_flag, *s_flag, *m_flag;
+ struct skill_unit *unit1;
+ struct skill_unit *unit2;
+ r_flag = (int *) malloc(sizeof(int) * group->unit_count);
+ s_flag = (int *) malloc(sizeof(int) * group->unit_count);
+ m_flag = (int *) malloc(sizeof(int) * group->unit_count);
+ memset(r_flag,0, sizeof(int) * group->unit_count);// 継承フラグ
+ memset(s_flag,0, sizeof(int) * group->unit_count);// 継承フラグ
+ memset(m_flag,0, sizeof(int) * group->unit_count);// 継承フラグ
+
+ //先にフラグを全部決める
+ for(i=0;i<group->unit_count;i++){
+ int move_check=0;// かぶりフラグ
+ unit1=&group->unit[i];
+ for(j=0;j<group->unit_count;j++){
+ unit2=&group->unit[j];
+ if(unit1->bl.m==m && unit1->bl.x+dx==unit2->bl.x && unit1->bl.y+dy==unit2->bl.y){
+ //移動先にユニットがかぶってたら
+ s_flag[i]=1;// 移動前のユニットナンバーの継承フラグon
+ r_flag[j]=1;// かぶるユニットナンバーの残留フラグon
+ move_check=1;//ユニットがかぶった。
+ break;
+ }
+ }
+ if(!move_check)// ユニットがかぶってなかったら
+ m_flag[i]=1;// 移動前ユニットナンバーの移動フラグon
+ }
+
+ //フラグに基づいてユニット移動
+ for(i=0;i<group->unit_count;i++){
+ unit1=&group->unit[i];
+ if(m_flag[i]){// 移動フラグがonで
+ if(!r_flag[i]){// 残留フラグがoffなら
+ //単純移動(rangeも継承の必要無し)
+ int range=unit1->range;
+ map_delblock(&unit1->bl);
+ unit1->bl.m = m;
+ unit1->bl.x += dx;
+ unit1->bl.y += dy;
+ map_addblock(&unit1->bl);
+ clif_skill_setunit(unit1);
+ if(range > 0){
+ if(range < 7)
+ range = 7;
+ map_foreachinarea( skill_unit_move_unit_group_sub, unit1->bl.m,
+ unit1->bl.x-range,unit1->bl.y-range,unit1->bl.x+range,unit1->bl.y+range,0,
+ &unit1->bl,gettick() );
+ }
+ }else{// 残留フラグがonなら
+ //空ユニットになるので、継承可能なユニットを探す
+ for(j=0;j<group->unit_count;j++){
+ unit2=&group->unit[j];
+ if(s_flag[j] && !r_flag[j]){
+ // 継承移動(range継承付き)
+ int range=unit1->range;
+ map_delblock(&unit2->bl);
+ unit2->bl.m = m;
+ unit2->bl.x = unit1->bl.x + dx;
+ unit2->bl.y = unit1->bl.y + dy;
+ unit2->range = unit1->range;
+ map_addblock(&unit2->bl);
+ clif_skill_setunit(unit2);
+ if(range > 0){
+ if(range < 7)
+ range = 7;
+ map_foreachinarea( skill_unit_move_unit_group_sub, unit2->bl.m,
+ unit2->bl.x-range,unit2->bl.y-range,unit2->bl.x+range,unit2->bl.y+range,0,
+ &unit2->bl,gettick() );
+ }
+ s_flag[j]=0;// 継承完了したのでoff
+ break;
+ }
+ }
+ }
+ }
+ }
+ free(r_flag);
+ free(s_flag);
+ free(m_flag);
+ }
+ }
+ return 0;
+}
+
+/*----------------------------------------------------------------------------
+ * アイテム合成
+ *----------------------------------------------------------------------------
+ */
+
+/*==========================================
+ * アイテム合成可能判定
+ *------------------------------------------
+ */
+int skill_can_produce_mix( struct map_session_data *sd, int nameid, int trigger )
+{
+ int i,j;
+
+ nullpo_retr(0, sd);
+
+ if(nameid<=0)
+ return 0;
+
+ for(i=0;i<MAX_SKILL_PRODUCE_DB;i++){
+ if(skill_produce_db[i].nameid == nameid )
+ break;
+ }
+ if( i >= MAX_SKILL_PRODUCE_DB ) /* データベースにない */
+ return 0;
+
+ if(trigger>=0){
+ if(trigger==32 || trigger==16 || trigger==64){
+ if(skill_produce_db[i].itemlv!=trigger) /* ファーマシー*ポーション類と溶鉱炉*鉱石以外はだめ */
+ return 0;
+ }else{
+ if(skill_produce_db[i].itemlv>=16) /* 武器以外はだめ */
+ return 0;
+ if( itemdb_wlv(nameid)>trigger ) /* 武器Lv判定 */
+ return 0;
+ }
+ }
+ if( (j=skill_produce_db[i].req_skill)>0 && pc_checkskill(sd,j)<=0 )
+ return 0; /* スキルが足りない */
+
+ for(j=0;j<5;j++){
+ int id,x,y;
+ if( (id=skill_produce_db[i].mat_id[j]) <= 0 ) /* これ以上は材料要らない */
+ continue;
+ if(skill_produce_db[i].mat_amount[j] <= 0) {
+ if(pc_search_inventory(sd,id) < 0)
+ return 0;
+ }
+ else {
+ for(y=0,x=0;y<MAX_INVENTORY;y++)
+ if( sd->status.inventory[y].nameid == id )
+ x+=sd->status.inventory[y].amount;
+ if(x<skill_produce_db[i].mat_amount[j]) /* アイテムが足りない */
+ return 0;
+ }
+ }
+ return i+1;
+}
+
+/*==========================================
+ * アイテム合成可能判定
+ *------------------------------------------
+ */
+int skill_produce_mix( struct map_session_data *sd,
+ int nameid, int slot1, int slot2, int slot3 )
+{
+ int slot[3];
+ int i,sc,ele,idx,equip,wlv,make_per,flag;
+
+ nullpo_retr(0, sd);
+
+ if( !(idx=skill_can_produce_mix(sd,nameid,-1)) ) /* 条件不足 */
+ return 0;
+ idx--;
+ slot[0]=slot1;
+ slot[1]=slot2;
+ slot[2]=slot3;
+
+ /* 埋め込み処理 */
+ for(i=0,sc=0,ele=0;i<3;i++){
+ int j;
+ if( slot[i]<=0 )
+ continue;
+ j = pc_search_inventory(sd,slot[i]);
+ if(j < 0) /* 不正パケット(アイテム存在)チェック */
+ continue;
+ if(slot[i]==1000){ /* 星のかけら */
+ pc_delitem(sd,j,1,1);
+ sc++;
+ }
+ if(slot[i]>=994 && slot[i]<=997 && ele==0){ /* 属性石 */
+ static const int ele_table[4]={3,1,4,2};
+ pc_delitem(sd,j,1,1);
+ ele=ele_table[slot[i]-994];
+ }
+ }
+
+ /* 材料消費 */
+ for(i=0;i<5;i++){
+ int j,id,x;
+ if( (id=skill_produce_db[idx].mat_id[i]) <= 0 )
+ continue;
+ x=skill_produce_db[idx].mat_amount[i]; /* 必要な個数 */
+ do{ /* 2つ以上のインデックスにまたがっているかもしれない */
+ int y=0;
+ j = pc_search_inventory(sd,id);
+
+ if(j >= 0){
+ y = sd->status.inventory[j].amount;
+ if(y>x)y=x; /* 足りている */
+ pc_delitem(sd,j,y,0);
+ }else {
+ if(battle_config.error_log)
+ printf("skill_produce_mix: material item error\n");
+ }
+
+ x-=y; /* まだ足りない個数を計算 */
+ }while( j>=0 && x>0 ); /* 材料を消費するか、エラーになるまで繰り返す */
+ }
+
+ /* 確率判定 */
+ equip = itemdb_isequip(nameid);
+ if(!equip) {
+ if(skill_produce_db[idx].req_skill==AM_PHARMACY) {
+ if((nameid >= 501 && nameid <= 506) || (nameid >= 545 && nameid <= 547) || nameid == 525)
+ make_per = 2000 + sd->status.base_level*30 + sd->paramc[3]*20 + sd->paramc[4]*15 + pc_checkskill(sd,AM_LEARNINGPOTION)*100 + pc_checkskill(sd,AM_PHARMACY)*300 + pc_checkskill(sd,AM_POTIONPITCHER)*100;
+ else if(nameid == 970)
+ make_per = 1500 + sd->status.base_level*30 + sd->paramc[3]*20 + sd->paramc[4]*15 + pc_checkskill(sd,AM_LEARNINGPOTION)*100 + pc_checkskill(sd,AM_PHARMACY)*300;
+ else if(nameid == 7135)
+ make_per = 1000 + sd->status.base_level*30 + sd->paramc[3]*20 + sd->paramc[4]*15 + pc_checkskill(sd,AM_LEARNINGPOTION)*100 + pc_checkskill(sd,AM_PHARMACY)*300 + pc_checkskill(sd,AM_DEMONSTRATION)*100;
+ else if(nameid == 7136)
+ make_per = 1000 + sd->status.base_level*30 + sd->paramc[3]*20 + sd->paramc[4]*15 + pc_checkskill(sd,AM_LEARNINGPOTION)*100 + pc_checkskill(sd,AM_PHARMACY)*300 + pc_checkskill(sd,AM_ACIDTERROR)*100;
+ else if(nameid == 7137)
+ make_per = 1000 + sd->status.base_level*30 + sd->paramc[3]*20 + sd->paramc[4]*15 + pc_checkskill(sd,AM_LEARNINGPOTION)*100 + pc_checkskill(sd,AM_PHARMACY)*300 + pc_checkskill(sd,AM_CANNIBALIZE)*100;
+ else if(nameid == 7138)
+ make_per = 1000 + sd->status.base_level*30 + sd->paramc[3]*20 + sd->paramc[4]*15 + pc_checkskill(sd,AM_LEARNINGPOTION)*100 + pc_checkskill(sd,AM_PHARMACY)*300 + pc_checkskill(sd,AM_SPHEREMINE)*100;
+ else if(nameid == 7139)
+ make_per = 1000 + sd->status.base_level*30 + sd->paramc[3]*20 + sd->paramc[4]*15 + pc_checkskill(sd,AM_LEARNINGPOTION)*100 + pc_checkskill(sd,AM_PHARMACY)*300 + pc_checkskill(sd,AM_CP_WEAPON)*100 +
+ pc_checkskill(sd,AM_CP_SHIELD)*100 + pc_checkskill(sd,AM_CP_ARMOR)*100 + pc_checkskill(sd,AM_CP_HELM)*100;
+ else
+ make_per = 1000 + sd->status.base_level*30 + sd->paramc[3]*20 + sd->paramc[4]*15 + pc_checkskill(sd,AM_LEARNINGPOTION)*100 + pc_checkskill(sd,AM_PHARMACY)*300;
+ }
+ else {
+ if(nameid == 998)
+ make_per = 2000 + sd->status.base_level*30 + sd->paramc[4]*20 + sd->paramc[5]*10 + pc_checkskill(sd,skill_produce_db[idx].req_skill)*600;
+ else if(nameid == 985)
+ make_per = 1000 + sd->status.base_level*30 + sd->paramc[4]*20 + sd->paramc[5]*10 + (pc_checkskill(sd,skill_produce_db[idx].req_skill)-1)*500;
+ else
+ make_per = 1000 + sd->status.base_level*30 + sd->paramc[4]*20 + sd->paramc[5]*10 + pc_checkskill(sd,skill_produce_db[idx].req_skill)*500;
+ }
+ }
+ else {
+ int add_per;
+ if(pc_search_inventory(sd,989) >= 0) add_per = 750;
+ else if(pc_search_inventory(sd,988) >= 0) add_per = 500;
+ else if(pc_search_inventory(sd,987) >= 0) add_per = 250;
+ else if(pc_search_inventory(sd,986) >= 0) add_per = 0;
+ else add_per = -500;
+ if(ele) add_per -= 500;
+ add_per -= sc*500;
+ wlv = itemdb_wlv(nameid);
+ make_per = ((250 + sd->status.base_level*15 + sd->paramc[4]*10 + sd->paramc[5]*5 + pc_checkskill(sd,skill_produce_db[idx].req_skill)*500 +
+ add_per) * (100 - (wlv - 1)*20))/100 + pc_checkskill(sd,BS_WEAPONRESEARCH)*100 + ((wlv >= 3)? pc_checkskill(sd,BS_ORIDEOCON)*100 : 0);
+ }
+
+ if(make_per < 1) make_per = 1;
+
+ if(skill_produce_db[idx].req_skill==AM_PHARMACY) {
+ if( battle_config.pp_rate!=100 )
+ make_per=make_per*battle_config.pp_rate/100;
+ }
+ else {
+ if( battle_config.wp_rate!=100 ) /* 確率補正 */
+ make_per=make_per*battle_config.wp_rate/100;
+ }
+
+// if(battle_config.etc_log)
+// printf("make rate = %d\n",make_per);
+
+ if(rand()%10000 < make_per){
+ /* 成功 */
+ struct item tmp_item;
+ memset(&tmp_item,0,sizeof(tmp_item));
+ tmp_item.nameid=nameid;
+ tmp_item.amount=1;
+ tmp_item.identify=1;
+ if(equip){ /* 武器の場合 */
+ tmp_item.card[0]=0x00ff; /* 製造武器フラグ */
+ tmp_item.card[1]=((sc*5)<<8)+ele; /* 属性とつよさ */
+ *((unsigned long *)(&tmp_item.card[2]))=sd->char_id; /* キャラID */
+ }
+ else if((battle_config.produce_item_name_input && skill_produce_db[idx].req_skill!=AM_PHARMACY) ||
+ (battle_config.produce_potion_name_input && skill_produce_db[idx].req_skill==AM_PHARMACY)) {
+ tmp_item.card[0]=0x00fe;
+ tmp_item.card[1]=0;
+ *((unsigned long *)(&tmp_item.card[2]))=sd->char_id; /* キャラID */
+ }
+
+ #ifndef TXT_ONLY
+ if(log_config.produce > 0)
+ log_produce(sd,nameid,slot1,slot2,slot3,1);
+ #endif //USE_SQL
+
+ if(skill_produce_db[idx].req_skill!=AM_PHARMACY && skill_produce_db[idx].req_skill!=WS_CREATECOIN) { //武器製造の場合
+ clif_produceeffect(sd,0,nameid);/* 武器製造エフェクトパケット */
+ clif_misceffect(&sd->bl,3); /* 他人にも成功を通知(精錬成功エフェクトと同じでいいの?) */
+ }
+ else if(skill_produce_db[idx].req_skill==AM_PHARMACY){ //ファーマシーの場合
+ clif_produceeffect(sd,2,nameid);/* 製薬エフェクトパケット */
+ clif_misceffect(&sd->bl,5); /* 他人にも成功を通知*/
+ }else{
+ clif_produceeffect(sd,0,nameid);/* 不明なのでとりあえず製造エフェクトパケット */
+ clif_misceffect(&sd->bl,3); /* 他人にも成功を通知*/
+ }
+
+ if((flag = pc_additem(sd,&tmp_item,1))) {
+ clif_additem(sd,0,0,flag);
+ map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
+ }
+ }
+ else {
+ #ifndef TXT_ONLY
+ if(log_config.produce > 0)
+ log_produce(sd,nameid,slot1,slot2,slot3,0);
+ #endif //USE_SQL
+
+ if(skill_produce_db[idx].req_skill!=AM_PHARMACY) { //武器製造の場合
+ clif_produceeffect(sd,1,nameid);/* 武器製造失敗エフェクトパケット */
+ clif_misceffect(&sd->bl,2); /* 他人にも失敗を通知 */
+ }
+ else if(skill_produce_db[idx].req_skill==AM_PHARMACY){ //ファーマシーの場合
+ clif_produceeffect(sd,3,nameid);/* 製薬失敗エフェクトパケット */
+ clif_misceffect(&sd->bl,6); /* 他人にも失敗を通知*/
+ }else{
+ clif_produceeffect(sd,1,nameid);/* 不明なのでとりあえず製造失敗エフェクトパケット */
+ clif_misceffect(&sd->bl,2); /* 他人にも失敗を通知*/
+ }
+ }
+ return 0;
+}
+
+int skill_arrow_create( struct map_session_data *sd,int nameid)
+{
+ int i,j,flag,index=-1;
+ struct item tmp_item;
+
+ nullpo_retr(0, sd);
+
+ if(nameid <= 0)
+ return 1;
+
+ for(i=0;i<MAX_SKILL_ARROW_DB;i++)
+ if(nameid == skill_arrow_db[i].nameid) {
+ index = i;
+ break;
+ }
+
+ if(index < 0 || (j = pc_search_inventory(sd,nameid)) < 0)
+ return 1;
+
+ pc_delitem(sd,j,1,0);
+ for(i=0;i<5;i++) {
+ memset(&tmp_item,0,sizeof(tmp_item));
+ tmp_item.identify = 1;
+ tmp_item.nameid = skill_arrow_db[index].cre_id[i];
+ tmp_item.amount = skill_arrow_db[index].cre_amount[i];
+ if(battle_config.making_arrow_name_input) {
+ tmp_item.card[0]=0x00fe;
+ tmp_item.card[1]=0;
+ *((unsigned long *)(&tmp_item.card[2]))=sd->char_id; /* キャラID */
+ }
+ if(tmp_item.nameid <= 0 || tmp_item.amount <= 0)
+ continue;
+ if((flag = pc_additem(sd,&tmp_item,tmp_item.amount))) {
+ clif_additem(sd,0,0,flag);
+ map_addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
+ }
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------
+ * 初期化系
+ */
+
+/*==========================================
+ * スキル関係ファイル読み込み
+ * skill_db.txt スキルデータ
+ * skill_cast_db.txt スキルの詠唱時間とディレイデータ
+ * produce_db.txt アイテム作成スキル用データ
+ * create_arrow_db.txt 矢作成スキル用データ
+ * abra_db.txt アブラカダブラ発動スキルデータ
+ *------------------------------------------
+ */
+int skill_readdb(void)
+{
+ int i,j,k,l,m;
+ FILE *fp;
+ char line[1024],*p;
+ char *filename[]={"db/produce_db.txt","db/produce_db2.txt"};
+
+ /* スキルデータベース */
+ memset(skill_db,0,sizeof(skill_db));
+ fp=fopen("db/skill_db.txt","r");
+ if(fp==NULL){
+ printf("can't read db/skill_db.txt\n");
+ return 1;
+ }
+ while(fgets(line,1020,fp)){
+ char *split[50], *split2[MAX_SKILL_LEVEL];
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ for(j=0,p=line;j<14 && p;j++){
+ split[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+ if(split[13]==NULL || j<14)
+ continue;
+
+ i=atoi(split[0]);
+ if(i<0 || i>MAX_SKILL_DB)
+ continue;
+
+/* printf("skill id=%d\n",i); */
+ memset(split2,0,sizeof(split2));
+ for(j=0,p=split[1];j<MAX_SKILL_LEVEL && p;j++){
+ split2[j]=p;
+ p=strchr(p,':');
+ if(p) *p++=0;
+ }
+ for(k=0;k<MAX_SKILL_LEVEL;k++)
+ skill_db[i].range[k]=(split2[k])? atoi(split2[k]):atoi(split2[0]);
+ skill_db[i].hit=atoi(split[2]);
+ skill_db[i].inf=atoi(split[3]);
+ skill_db[i].pl=atoi(split[4]);
+ skill_db[i].nk=atoi(split[5]);
+ skill_db[i].max=atoi(split[6]);
+
+ memset(split2,0,sizeof(split2));
+ for(j=0,p=split[7];j<MAX_SKILL_LEVEL && p;j++){
+ split2[j]=p;
+ p=strchr(p,':');
+ if(p) *p++=0;
+ }
+ for(k=0;k<MAX_SKILL_LEVEL;k++)
+ skill_db[i].num[k]=(split2[k])? atoi(split2[k]):atoi(split2[0]);
+
+ if(strcmpi(split[8],"yes") == 0)
+ skill_db[i].castcancel=1;
+ else
+ skill_db[i].castcancel=0;
+ skill_db[i].cast_def_rate=atoi(split[9]);
+ skill_db[i].inf2=atoi(split[10]);
+ skill_db[i].maxcount=atoi(split[11]);
+ if(strcmpi(split[12],"weapon") == 0)
+ skill_db[i].skill_type=BF_WEAPON;
+ else if(strcmpi(split[12],"magic") == 0)
+ skill_db[i].skill_type=BF_MAGIC;
+ else if(strcmpi(split[12],"misc") == 0)
+ skill_db[i].skill_type=BF_MISC;
+ else
+ skill_db[i].skill_type=0;
+ memset(split2,0,sizeof(split2));
+ for(j=0,p=split[13];j<MAX_SKILL_LEVEL && p;j++){
+ split2[j]=p;
+ p=strchr(p,':');
+ if(p) *p++=0;
+ }
+ for(k=0;k<MAX_SKILL_LEVEL;k++)
+ skill_db[i].blewcount[k]=(split2[k])? atoi(split2[k]):atoi(split2[0]);
+ }
+ fclose(fp);
+ printf("read db/skill_db.txt done\n");
+
+ fp=fopen("db/skill_require_db.txt","r");
+ if(fp==NULL){
+ printf("can't read db/skill_require_db.txt\n");
+ return 1;
+ }
+ while(fgets(line,1020,fp)){
+ char *split[51], *split2[MAX_SKILL_LEVEL];
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ for(j=0,p=line;j<30 && p;j++){
+ split[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+ if(split[29]==NULL || j<30)
+ continue;
+
+ i=atoi(split[0]);
+ if(i<0 || i>MAX_SKILL_DB)
+ continue;
+
+ memset(split2,0,sizeof(split2));
+ for(j=0,p=split[1];j<MAX_SKILL_LEVEL && p;j++){
+ split2[j]=p;
+ p=strchr(p,':');
+ if(p) *p++=0;
+ }
+ for(k=0;k<MAX_SKILL_LEVEL;k++)
+ skill_db[i].hp[k]=(split2[k])? atoi(split2[k]):atoi(split2[0]);
+
+ memset(split2,0,sizeof(split2));
+ for(j=0,p=split[2];j<MAX_SKILL_LEVEL && p;j++){
+ split2[j]=p;
+ p=strchr(p,':');
+ if(p) *p++=0;
+ }
+ for(k=0;k<MAX_SKILL_LEVEL;k++)
+ skill_db[i].mhp[k]=(split2[k])? atoi(split2[k]):atoi(split2[0]);
+
+ memset(split2,0,sizeof(split2));
+ for(j=0,p=split[3];j<MAX_SKILL_LEVEL && p;j++){
+ split2[j]=p;
+ p=strchr(p,':');
+ if(p) *p++=0;
+ }
+ for(k=0;k<MAX_SKILL_LEVEL;k++)
+ skill_db[i].sp[k]=(split2[k])? atoi(split2[k]):atoi(split2[0]);
+
+ memset(split2,0,sizeof(split2));
+ for(j=0,p=split[4];j<MAX_SKILL_LEVEL && p;j++){
+ split2[j]=p;
+ p=strchr(p,':');
+ if(p) *p++=0;
+ }
+ for(k=0;k<MAX_SKILL_LEVEL;k++)
+ skill_db[i].hp_rate[k]=(split2[k])? atoi(split2[k]):atoi(split2[0]);
+
+ memset(split2,0,sizeof(split2));
+ for(j=0,p=split[5];j<MAX_SKILL_LEVEL && p;j++){
+ split2[j]=p;
+ p=strchr(p,':');
+ if(p) *p++=0;
+ }
+ for(k=0;k<MAX_SKILL_LEVEL;k++)
+ skill_db[i].sp_rate[k]=(split2[k])? atoi(split2[k]):atoi(split2[0]);
+
+ memset(split2,0,sizeof(split2));
+ for(j=0,p=split[6];j<MAX_SKILL_LEVEL && p;j++){
+ split2[j]=p;
+ p=strchr(p,':');
+ if(p) *p++=0;
+ }
+ for(k=0;k<MAX_SKILL_LEVEL;k++)
+ skill_db[i].zeny[k]=(split2[k])? atoi(split2[k]):atoi(split2[0]);
+
+ memset(split2,0,sizeof(split2));
+ for(j=0,p=split[7];j<32 && p;j++){
+ split2[j]=p;
+ p=strchr(p,':');
+ if(p) *p++=0;
+ }
+ for(k=0;k<32 && split2[k];k++) {
+ l = atoi(split2[k]);
+ if(l == 99) {
+ skill_db[i].weapon = 0xffffffff;
+ break;
+ }
+ else
+ skill_db[i].weapon |= 1<<l;
+ }
+
+ if( strcmpi(split[8],"hiding")==0 ) skill_db[i].state=ST_HIDING;
+ else if( strcmpi(split[8],"cloaking")==0 ) skill_db[i].state=ST_CLOAKING;
+ else if( strcmpi(split[8],"hidden")==0 ) skill_db[i].state=ST_HIDDEN;
+ else if( strcmpi(split[8],"riding")==0 ) skill_db[i].state=ST_RIDING;
+ else if( strcmpi(split[8],"falcon")==0 ) skill_db[i].state=ST_FALCON;
+ else if( strcmpi(split[8],"cart")==0 ) skill_db[i].state=ST_CART;
+ else if( strcmpi(split[8],"shield")==0 ) skill_db[i].state=ST_SHIELD;
+ else if( strcmpi(split[8],"sight")==0 ) skill_db[i].state=ST_SIGHT;
+ else if( strcmpi(split[8],"explosionspirits")==0 ) skill_db[i].state=ST_EXPLOSIONSPIRITS;
+ else if( strcmpi(split[8],"recover_weight_rate")==0 ) skill_db[i].state=ST_RECOV_WEIGHT_RATE;
+ else if( strcmpi(split[8],"move_enable")==0 ) skill_db[i].state=ST_MOVE_ENABLE;
+ else if( strcmpi(split[8],"water")==0 ) skill_db[i].state=ST_WATER;
+ else skill_db[i].state=ST_NONE;
+
+ memset(split2,0,sizeof(split2));
+ for(j=0,p=split[9];j<MAX_SKILL_LEVEL && p;j++){
+ split2[j]=p;
+ p=strchr(p,':');
+ if(p) *p++=0;
+ }
+ for(k=0;k<MAX_SKILL_LEVEL;k++)
+ skill_db[i].spiritball[k]=(split2[k])? atoi(split2[k]):atoi(split2[0]);
+ skill_db[i].itemid[0]=atoi(split[10]);
+ skill_db[i].amount[0]=atoi(split[11]);
+ skill_db[i].itemid[1]=atoi(split[12]);
+ skill_db[i].amount[1]=atoi(split[13]);
+ skill_db[i].itemid[2]=atoi(split[14]);
+ skill_db[i].amount[2]=atoi(split[15]);
+ skill_db[i].itemid[3]=atoi(split[16]);
+ skill_db[i].amount[3]=atoi(split[17]);
+ skill_db[i].itemid[4]=atoi(split[18]);
+ skill_db[i].amount[4]=atoi(split[19]);
+ skill_db[i].itemid[5]=atoi(split[20]);
+ skill_db[i].amount[5]=atoi(split[21]);
+ skill_db[i].itemid[6]=atoi(split[22]);
+ skill_db[i].amount[6]=atoi(split[23]);
+ skill_db[i].itemid[7]=atoi(split[24]);
+ skill_db[i].amount[7]=atoi(split[25]);
+ skill_db[i].itemid[8]=atoi(split[26]);
+ skill_db[i].amount[8]=atoi(split[27]);
+ skill_db[i].itemid[9]=atoi(split[28]);
+ skill_db[i].amount[9]=atoi(split[29]);
+ }
+ fclose(fp);
+ printf("read db/skill_require_db.txt done\n");
+
+ /* キャスティングデータベース */
+ fp=fopen("db/skill_cast_db.txt","r");
+ if(fp==NULL){
+ printf("can't read db/skill_cast_db.txt\n");
+ return 1;
+ }
+ while(fgets(line,1020,fp)){
+ char *split[50], *split2[MAX_SKILL_LEVEL];
+ memset(split,0,sizeof(split)); // [Valaris] thanks to fov
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ for(j=0,p=line;j<5 && p;j++){
+ split[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+ if(split[4]==NULL || j<5)
+ continue;
+
+ i=atoi(split[0]);
+ if(i<0 || i>MAX_SKILL_DB)
+ continue;
+
+ memset(split2,0,sizeof(split2));
+ for(j=0,p=split[1];j<MAX_SKILL_LEVEL && p;j++){
+ split2[j]=p;
+ p=strchr(p,':');
+ if(p) *p++=0;
+ }
+ for(k=0;k<MAX_SKILL_LEVEL;k++)
+ skill_db[i].cast[k]=(split2[k])? atoi(split2[k]):atoi(split2[0]);
+
+ memset(split2,0,sizeof(split2));
+ for(j=0,p=split[2];j<MAX_SKILL_LEVEL && p;j++){
+ split2[j]=p;
+ p=strchr(p,':');
+ if(p) *p++=0;
+ }
+ for(k=0;k<MAX_SKILL_LEVEL;k++)
+ skill_db[i].delay[k]=(split2[k])? atoi(split2[k]):atoi(split2[0]);
+
+ memset(split2,0,sizeof(split2));
+ for(j=0,p=split[3];j<MAX_SKILL_LEVEL && p;j++){
+ split2[j]=p;
+ p=strchr(p,':');
+ if(p) *p++=0;
+ }
+ for(k=0;k<MAX_SKILL_LEVEL;k++)
+ skill_db[i].upkeep_time[k]=(split2[k])? atoi(split2[k]):atoi(split2[0]);
+
+ memset(split2,0,sizeof(split2));
+ for(j=0,p=split[4];j<MAX_SKILL_LEVEL && p;j++){
+ split2[j]=p;
+ p=strchr(p,':');
+ if(p) *p++=0;
+ }
+ for(k=0;k<MAX_SKILL_LEVEL;k++)
+ skill_db[i].upkeep_time2[k]=(split2[k])? atoi(split2[k]):atoi(split2[0]);
+ }
+ fclose(fp);
+ printf("read db/skill_cast_db.txt done\n");
+
+ /* 製造系スキルデータベース */
+ memset(skill_produce_db,0,sizeof(skill_produce_db));
+ for(m=0;m<2;m++){
+ fp=fopen(filename[m],"r");
+ if(fp==NULL){
+ if(m>0)
+ continue;
+ printf("can't read %s\n",filename[m]);
+ return 1;
+ }
+ k=0;
+ while(fgets(line,1020,fp)){
+ char *split[16];
+ int x,y;
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ memset(split,0,sizeof(split));
+ for(j=0,p=line;j<13 && p;j++){
+ split[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+ if(split[0]==NULL)
+ continue;
+ i=atoi(split[0]);
+ if(i<=0)
+ continue;
+
+ skill_produce_db[k].nameid=i;
+ skill_produce_db[k].itemlv=atoi(split[1]);
+ skill_produce_db[k].req_skill=atoi(split[2]);
+
+ for(x=3,y=0;split[x] && split[x+1] && y<5;x+=2,y++){
+ skill_produce_db[k].mat_id[y]=atoi(split[x]);
+ skill_produce_db[k].mat_amount[y]=atoi(split[x+1]);
+ }
+ k++;
+ if(k >= MAX_SKILL_PRODUCE_DB)
+ break;
+ }
+ fclose(fp);
+ printf("read %s done (count=%d)\n",filename[m],k);
+ }
+
+ memset(skill_arrow_db,0,sizeof(skill_arrow_db));
+ fp=fopen("db/create_arrow_db.txt","r");
+ if(fp==NULL){
+ printf("can't read db/create_arrow_db.txt\n");
+ return 1;
+ }
+ k=0;
+ while(fgets(line,1020,fp)){
+ char *split[16];
+ int x,y;
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ memset(split,0,sizeof(split));
+ for(j=0,p=line;j<13 && p;j++){
+ split[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+ if(split[0]==NULL)
+ continue;
+ i=atoi(split[0]);
+ if(i<=0)
+ continue;
+
+ skill_arrow_db[k].nameid=i;
+
+ for(x=1,y=0;split[x] && split[x+1] && y<5;x+=2,y++){
+ skill_arrow_db[k].cre_id[y]=atoi(split[x]);
+ skill_arrow_db[k].cre_amount[y]=atoi(split[x+1]);
+ }
+ k++;
+ if(k >= MAX_SKILL_ARROW_DB)
+ break;
+ }
+ fclose(fp);
+ printf("read db/create_arrow_db.txt done (count=%d)\n",k);
+
+ memset(skill_abra_db,0,sizeof(skill_abra_db));
+ fp=fopen("db/abra_db.txt","r");
+ if(fp==NULL){
+ printf("can't read db/abra_db.txt\n");
+ return 1;
+ }
+ k=0;
+ while(fgets(line,1020,fp)){
+ char *split[16];
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ memset(split,0,sizeof(split));
+ for(j=0,p=line;j<13 && p;j++){
+ split[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+ if(split[0]==NULL)
+ continue;
+ i=atoi(split[0]);
+ if(i<=0)
+ continue;
+
+ skill_abra_db[i].req_lv=atoi(split[2]);
+ skill_abra_db[i].per=atoi(split[3]);
+
+ k++;
+ if(k >= MAX_SKILL_ABRA_DB)
+ break;
+ }
+ fclose(fp);
+ printf("read db/abra_db.txt done (count=%d)\n",k);
+
+ fp=fopen("db/skill_castnodex_db.txt","r");
+ if(fp==NULL){
+ printf("can't read db/skill_castnodex_db.txt\n");
+ return 1;
+ }
+ while(fgets(line,1020,fp)){
+ char *split[50], *split2[MAX_SKILL_LEVEL];
+ memset(split,0,sizeof(split));
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ for(j=0,p=line;j<2 && p;j++){
+ split[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+
+ i=atoi(split[0]);
+ if(i<0 || i>MAX_SKILL_DB)
+ continue;
+
+ memset(split2,0,sizeof(split2));
+ for(j=0,p=split[1];j<MAX_SKILL_LEVEL && p;j++){
+ split2[j]=p;
+ p=strchr(p,':');
+ if(p) *p++=0;
+ }
+ for(k=0;k<MAX_SKILL_LEVEL;k++)
+ skill_db[i].castnodex[k]=(split2[k])? atoi(split2[k]):atoi(split2[0]);
+ }
+ fclose(fp);
+ printf("read db/skill_castnodex_db.txt done\n");
+
+ return 0;
+}
+
+void skill_reload(void)
+{
+ /*
+
+ <empty skill database>
+ <?>
+
+ */
+
+ do_init_skill();
+}
+
+/*==========================================
+ * スキル関係初期化処理
+ *------------------------------------------
+ */
+int do_init_skill(void)
+{
+ skill_readdb();
+
+ add_timer_func_list(skill_unit_timer,"skill_unit_timer");
+ add_timer_func_list(skill_castend_id,"skill_castend_id");
+ add_timer_func_list(skill_castend_pos,"skill_castend_pos");
+ add_timer_func_list(skill_timerskill,"skill_timerskill");
+ add_timer_func_list(skill_status_change_timer,"skill_status_change_timer");
+ add_timer_interval(gettick()+SKILLUNITTIMER_INVERVAL,skill_unit_timer,0,0,SKILLUNITTIMER_INVERVAL);
+
+ return 0;
+}
diff --git a/src/map/skill.h b/src/map/skill.h
new file mode 100644
index 000000000..468e5d3af
--- /dev/null
+++ b/src/map/skill.h
@@ -0,0 +1,854 @@
+// $Id: skill.h,v 1.5 2004/09/25 05:32:19 MouseJstr Exp $
+#ifndef _SKILL_H_
+#define _SKILL_H_
+
+#include "map.h"
+
+#define MAX_SKILL_DB 450
+#define MAX_SKILL_PRODUCE_DB 150
+#define MAX_SKILL_ARROW_DB 150
+#define MAX_SKILL_ABRA_DB 350
+
+// スキルデータベース
+struct skill_db {
+ int range[MAX_SKILL_LEVEL],hit,inf,pl,nk,max;
+ int num[MAX_SKILL_LEVEL];
+ int cast[MAX_SKILL_LEVEL],delay[MAX_SKILL_LEVEL];
+ int upkeep_time[MAX_SKILL_LEVEL],upkeep_time2[MAX_SKILL_LEVEL];
+ int castcancel,cast_def_rate;
+ int inf2,maxcount,skill_type;
+ int blewcount[MAX_SKILL_LEVEL];
+ int hp[MAX_SKILL_LEVEL],sp[MAX_SKILL_LEVEL],mhp[MAX_SKILL_LEVEL],hp_rate[MAX_SKILL_LEVEL],sp_rate[MAX_SKILL_LEVEL],zeny[MAX_SKILL_LEVEL];
+ int weapon,state,spiritball[MAX_SKILL_LEVEL];
+ int itemid[10],amount[10];
+ int castnodex[MAX_SKILL_LEVEL];
+};
+extern struct skill_db skill_db[MAX_SKILL_DB];
+
+struct skill_name_db {
+ int id; // skill id
+ char *name; // search strings
+ char *desc; // description that shows up for search's
+};
+extern struct skill_name_db skill_names[];
+
+// アイテム作成データベース
+struct skill_produce_db {
+ int nameid, trigger;
+ int req_skill,itemlv;
+ int mat_id[5],mat_amount[5];
+};
+extern struct skill_produce_db skill_produce_db[MAX_SKILL_PRODUCE_DB];
+
+// 矢作成データベース
+struct skill_arrow_db {
+ int nameid, trigger;
+ int cre_id[5],cre_amount[5];
+};
+extern struct skill_arrow_db skill_arrow_db[MAX_SKILL_ARROW_DB];
+
+// アブラカダブラデータベース
+struct skill_abra_db {
+ int nameid;
+ int req_lv;
+ int per;
+};
+extern struct skill_abra_db skill_abra_db[MAX_SKILL_ABRA_DB];
+
+struct block_list;
+struct map_session_data;
+struct skill_unit;
+struct skill_unit_group;
+
+int do_init_skill(void);
+
+// スキルデータベースへのアクセサ
+int skill_get_hit( int id );
+int skill_get_inf( int id );
+int skill_get_pl( int id );
+int skill_get_nk( int id );
+int skill_get_max( int id );
+int skill_get_range( int id , int lv );
+int skill_get_hp( int id ,int lv );
+int skill_get_mhp( int id ,int lv );
+int skill_get_sp( int id ,int lv );
+int skill_get_zeny( int id ,int lv );
+int skill_get_num( int id ,int lv );
+int skill_get_cast( int id ,int lv );
+int skill_get_delay( int id ,int lv );
+int skill_get_time( int id ,int lv );
+int skill_get_time2( int id ,int lv );
+int skill_get_castdef( int id );
+int skill_get_weapontype( int id );
+int skill_get_unit_id(int id,int flag);
+int skill_get_inf2( int id );
+int skill_get_maxcount( int id );
+int skill_get_blewcount( int id ,int lv );
+
+// スキルの使用
+int skill_use_id( struct map_session_data *sd, int target_id,
+ int skill_num,int skill_lv);
+int skill_use_pos( struct map_session_data *sd,
+ int skill_x, int skill_y, int skill_num, int skill_lv);
+
+int skill_castend_map( struct map_session_data *sd,int skill_num, const char *map);
+
+int skill_cleartimerskill(struct block_list *src);
+int skill_addtimerskill(struct block_list *src,unsigned int tick,int target,int x,int y,int skill_id,int skill_lv,int type,int flag);
+
+// 追加効果
+int skill_additional_effect( struct block_list* src, struct block_list *bl,int skillid,int skilllv,int attack_type,unsigned int tick);
+
+// ユニットスキル
+struct skill_unit *skill_initunit(struct skill_unit_group *group,int idx,int x,int y);
+int skill_delunit(struct skill_unit *unit);
+struct skill_unit_group *skill_initunitgroup(struct block_list *src,
+ int count,int skillid,int skilllv,int unit_id);
+int skill_delunitgroup(struct skill_unit_group *group);
+struct skill_unit_group_tickset *skill_unitgrouptickset_search(
+ struct block_list *bl,int group_id);
+int skill_unitgrouptickset_delete(struct block_list *bl,int group_id);
+int skill_clear_unitgroup(struct block_list *src);
+
+int skill_unit_ondamaged(struct skill_unit *src,struct block_list *bl,
+ int damage,unsigned int tick);
+
+int skill_castfix( struct block_list *bl, int time );
+int skill_delayfix( struct block_list *bl, int time );
+int skill_check_unit_range(int m,int x,int y,int range,int skillid);
+int skill_check_unit_range2(int m,int x,int y,int range);
+// -- moonsoul (added skill_check_unit_cell)
+int skill_check_unit_cell(int skillid,int m,int x,int y,int unit_id);
+int skill_unit_out_all( struct block_list *bl,unsigned int tick,int range);
+int skill_unit_move( struct block_list *bl,unsigned int tick,int range);
+int skill_unit_move_unit_group( struct skill_unit_group *group, int m,int dx,int dy);
+
+struct skill_unit_group *skill_check_dancing( struct block_list *src );
+void skill_stop_dancing(struct block_list *src, int flag);
+
+// 詠唱キャンセル
+int skill_castcancel(struct block_list *bl,int type);
+
+int skill_gangsterparadise(struct map_session_data *sd ,int type);
+void skill_brandishspear_first(struct square *tc,int dir,int x,int y);
+void skill_brandishspear_dir(struct square *tc,int dir,int are);
+int skill_autospell(struct map_session_data *md,int skillid);
+void skill_devotion(struct map_session_data *md,int target);
+void skill_devotion2(struct block_list *bl,int crusader);
+int skill_devotion3(struct block_list *bl,int target);
+void skill_devotion_end(struct map_session_data *md,struct map_session_data *sd,int target);
+
+#define skill_calc_heal(bl,skill_lv) (( battle_get_lv(bl)+battle_get_int(bl) )/8 *(4+ skill_lv*8))
+
+// その他
+int skill_check_cloaking(struct block_list *bl);
+int skill_type_cloaking(struct block_list *bl);
+int skill_is_danceskill(int id);
+
+// ステータス異常
+int skill_status_change_start(struct block_list *bl,int type,int val1,int val2,int val3,int val4,int tick,int flag);
+int skill_status_change_timer(int tid, unsigned int tick, int id, int data);
+int skill_encchant_eremental_end(struct block_list *bl, int type);
+int skill_status_change_end( struct block_list* bl , int type,int tid );
+int skill_status_change_clear(struct block_list *bl,int type);
+int skillnotok(int skillid, struct map_session_data *sd);
+
+// アイテム作成
+int skill_can_produce_mix( struct map_session_data *sd, int nameid, int trigger );
+int skill_produce_mix( struct map_session_data *sd,
+ int nameid, int slot1, int slot2, int slot3 );
+
+int skill_arrow_create( struct map_session_data *sd,int nameid);
+
+// mobスキルのため
+int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag );
+int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag );
+int skill_castend_pos2( struct block_list *src, int x,int y,int skillid,int skilllv,unsigned int tick,int flag);
+
+// スキル攻撃一括処理
+int skill_attack( int attack_type, struct block_list* src, struct block_list *dsrc,
+ struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag );
+
+void skill_reload(void);
+
+enum {
+ ST_NONE,ST_HIDING,ST_CLOAKING,ST_HIDDEN,ST_RIDING,ST_FALCON,ST_CART,ST_SHIELD,ST_SIGHT,ST_EXPLOSIONSPIRITS,
+ ST_RECOV_WEIGHT_RATE,ST_MOVE_ENABLE,ST_WATER,
+};
+
+enum { // struct map_session_data の status_changeの番号テーブル
+// SC_SENDMAX未満はクライアントへの通知あり。
+// 2-2次職の値はなんかめちゃくちゃっぽいので暫定。たぶん変更されます。
+ SC_SENDMAX =128,
+ SC_PROVOKE = 0,
+ SC_ENDURE = 1,
+ SC_TWOHANDQUICKEN = 2,
+ SC_CONCENTRATE = 3,
+ SC_HIDING = 4,
+ SC_CLOAKING = 5,
+ SC_ENCPOISON = 6,
+ SC_POISONREACT = 7,
+ SC_QUAGMIRE = 8,
+ SC_ANGELUS = 9,
+ SC_BLESSING =10,
+ SC_SIGNUMCRUCIS =11,
+ SC_INCREASEAGI =12,
+ SC_DECREASEAGI =13,
+ SC_SLOWPOISON =14,
+ SC_IMPOSITIO =15,
+ SC_SUFFRAGIUM =16,
+ SC_ASPERSIO =17,
+ SC_BENEDICTIO =18,
+ SC_KYRIE =19,
+ SC_MAGNIFICAT =20,
+ SC_GLORIA =21,
+ SC_AETERNA =22,
+ SC_ADRENALINE =23,
+ SC_WEAPONPERFECTION =24,
+ SC_OVERTHRUST =25,
+ SC_MAXIMIZEPOWER =26,
+ SC_RIDING =27,
+ SC_FALCON =28,
+ SC_TRICKDEAD =29,
+ SC_LOUD =30,
+ SC_ENERGYCOAT =31,
+ SC_HALLUCINATION =34,
+ SC_WEIGHT50 =35,
+ SC_WEIGHT90 =36,
+ SC_SPEEDPOTION0 =37,
+ SC_SPEEDPOTION1 =38,
+ SC_SPEEDPOTION2 =39,
+ SC_STRIPWEAPON =50,
+ SC_STRIPSHIELD =51,
+ SC_STRIPARMOR =52,
+ SC_STRIPHELM =53,
+ SC_CP_WEAPON =54,
+ SC_CP_SHIELD =55,
+ SC_CP_ARMOR =56,
+ SC_CP_HELM =57,
+ SC_AUTOGUARD =58,
+ SC_REFLECTSHIELD =59,
+ SC_DEVOTION =60,
+ SC_PROVIDENCE =61,
+ SC_DEFENDER =62,
+ SC_AUTOSPELL =65,
+ SC_SPEARSQUICKEN =68,
+ SC_EXPLOSIONSPIRITS =86,
+ SC_STEELBODY =87,
+ SC_COMBO =89,
+ SC_FLAMELAUNCHER =90,
+ SC_FROSTWEAPON =91,
+ SC_LIGHTNINGLOADER =92,
+ SC_SEISMICWEAPON =93,
+ SC_AURABLADE =103, /* オーラブレード */
+ SC_PARRYING =104, /* パリイング */
+ SC_CONCENTRATION =105, /* コンセントレーション */
+ SC_TENSIONRELAX =106, /* テンションリラックス */
+ SC_BERSERK =107, /* バーサーク */
+ SC_ASSUMPTIO =110, /* アシャンプティオ */
+ SC_MAGICPOWER =113, /* 魔法力増幅 */
+ SC_TRUESIGHT =115, /* トゥルーサイト */
+ SC_WINDWALK =116, /* ウインドウォーク */
+ SC_MELTDOWN =117, /* メルトダウン */
+ SC_CARTBOOST =118, /* カートブースト */
+ SC_REJECTSWORD =120, /* リジェクトソード */
+ SC_MARIONETTE =121, /* マリオネットコントロール */
+ SC_HEADCRUSH =124, /* ヘッドクラッシュ */
+ SC_JOINTBEAT =125, /* ジョイントビート */
+
+ SC_STONE =128,
+ SC_FREEZE =129,
+ SC_STAN =130,
+ SC_SLEEP =131,
+ SC_POISON =132,
+ SC_CURSE =133,
+ SC_SILENCE =134,
+ SC_CONFUSION =135,
+ SC_BLIND =136,
+ SC_DIVINA = SC_SILENCE,
+
+ SC_SAFETYWALL =140,
+ SC_PNEUMA =141,
+ SC_WATERBALL =142,
+ SC_ANKLE =143,
+ SC_DANCING =144,
+ SC_KEEPING =145,
+ SC_BARRIER =146,
+
+ SC_MAGICROD =149,
+ SC_SIGHT =150,
+ SC_RUWACH =151,
+ SC_AUTOCOUNTER =152,
+ SC_VOLCANO =153,
+ SC_DELUGE =154,
+ SC_VIOLENTGALE =155,
+ SC_BLADESTOP_WAIT =156,
+ SC_BLADESTOP =157,
+ SC_EXTREMITYFIST =158,
+ SC_GRAFFITI =159,
+
+ SC_LULLABY =160,
+ SC_RICHMANKIM =161,
+ SC_ETERNALCHAOS =162,
+ SC_DRUMBATTLE =163,
+ SC_NIBELUNGEN =164,
+ SC_ROKISWEIL =165,
+ SC_INTOABYSS =166,
+ SC_SIEGFRIED =167,
+ SC_DISSONANCE =168,
+ SC_WHISTLE =169,
+ SC_ASSNCROS =170,
+ SC_POEMBRAGI =171,
+ SC_APPLEIDUN =172,
+ SC_UGLYDANCE =173,
+ SC_HUMMING =174,
+ SC_DONTFORGETME =175,
+ SC_FORTUNE =176,
+ SC_SERVICE4U =177,
+
+ SC_SPIDERWEB =180, /* スパイダーウェッブ */
+ SC_MEMORIZE =181, /* メモライズ */
+
+ SC_WEDDING =187, //結婚用(結婚衣裳になって歩くのが遅いとか)
+ SC_NOCHAT =188, //赤エモ状態
+ SC_SPLASHER =189, /* ベナムスプラッシャー */
+ SC_SELFDESTRUCTION =190, /* 自爆 */
+
+
+// Used by English Team
+ SC_BROKNARMOR =32,
+ SC_BROKNWEAPON =33,
+ SC_SIGHTTRASHER =73,
+ SC_BASILICA =125,
+ SC_ENSEMBLE =159,
+ SC_FOGWALL =178,
+ SC_GOSPEL =179,
+ SC_LANDPROTECTOR =182,
+ SC_ADAPTATION =183,
+ SC_CHASEWALK =184,
+ SC_ATKPOT =185, // [Valaris]
+ SC_MATKPOT =186, // [Valaris]
+ SC_MINDBREAKER =191,
+ SC_SPELLBREAKER =192,
+
+// -- testing various SC effects
+// SC_AURABLADE =81,
+// SC_CONCENTRATION =83,
+// SC_TENSIONRELAX =84,
+// SC_BERSERK =85,
+// SC_CALLSPIRITS =100,
+// SC_PARRYING =100,
+// SC_FREECAST =101,
+// SC_ABSORBSPIRIT =102,
+// SC_ASSUMPTIO =114,
+// SC_SHARPSHOOT =127,
+// SC_GANGSTER =184,
+// SC_CANNIBALIZE =186,
+// SC_SPHEREMINE =187,
+// SC_METEOSTORM =189,
+// SC_CASTCANCEL =190,
+// SC_SPIDERWEB =191,
+};
+extern int SkillStatusChangeTable[];
+
+enum {
+ NV_BASIC = 1,
+
+ SM_SWORD,
+ SM_TWOHAND,
+ SM_RECOVERY,
+ SM_BASH,
+ SM_PROVOKE,
+ SM_MAGNUM,
+ SM_ENDURE,
+
+ MG_SRECOVERY,
+ MG_SIGHT,
+ MG_NAPALMBEAT,
+ MG_SAFETYWALL,
+ MG_SOULSTRIKE,
+ MG_COLDBOLT,
+ MG_FROSTDIVER,
+ MG_STONECURSE,
+ MG_FIREBALL,
+ MG_FIREWALL,
+ MG_FIREBOLT,
+ MG_LIGHTNINGBOLT,
+ MG_THUNDERSTORM,
+
+ AL_DP,
+ AL_DEMONBANE,
+ AL_RUWACH,
+ AL_PNEUMA,
+ AL_TELEPORT,
+ AL_WARP,
+ AL_HEAL,
+ AL_INCAGI,
+ AL_DECAGI,
+ AL_HOLYWATER,
+ AL_CRUCIS,
+ AL_ANGELUS,
+ AL_BLESSING,
+ AL_CURE,
+
+ MC_INCCARRY,
+ MC_DISCOUNT,
+ MC_OVERCHARGE,
+ MC_PUSHCART,
+ MC_IDENTIFY,
+ MC_VENDING,
+ MC_MAMMONITE,
+
+ AC_OWL,
+ AC_VULTURE,
+ AC_CONCENTRATION,
+ AC_DOUBLE,
+ AC_SHOWER,
+
+ TF_DOUBLE,
+ TF_MISS,
+ TF_STEAL,
+ TF_HIDING,
+ TF_POISON,
+ TF_DETOXIFY,
+
+ ALL_RESURRECTION,
+
+ KN_SPEARMASTERY,
+ KN_PIERCE,
+ KN_BRANDISHSPEAR,
+ KN_SPEARSTAB,
+ KN_SPEARBOOMERANG,
+ KN_TWOHANDQUICKEN,
+ KN_AUTOCOUNTER,
+ KN_BOWLINGBASH,
+ KN_RIDING,
+ KN_CAVALIERMASTERY,
+
+ PR_MACEMASTERY,
+ PR_IMPOSITIO,
+ PR_SUFFRAGIUM,
+ PR_ASPERSIO,
+ PR_BENEDICTIO,
+ PR_SANCTUARY,
+ PR_SLOWPOISON,
+ PR_STRECOVERY,
+ PR_KYRIE,
+ PR_MAGNIFICAT,
+ PR_GLORIA,
+ PR_LEXDIVINA,
+ PR_TURNUNDEAD,
+ PR_LEXAETERNA,
+ PR_MAGNUS,
+
+ WZ_FIREPILLAR,
+ WZ_SIGHTRASHER,
+ WZ_FIREIVY,
+ WZ_METEOR,
+ WZ_JUPITEL,
+ WZ_VERMILION,
+ WZ_WATERBALL,
+ WZ_ICEWALL,
+ WZ_FROSTNOVA,
+ WZ_STORMGUST,
+ WZ_EARTHSPIKE,
+ WZ_HEAVENDRIVE,
+ WZ_QUAGMIRE,
+ WZ_ESTIMATION,
+
+ BS_IRON,
+ BS_STEEL,
+ BS_ENCHANTEDSTONE,
+ BS_ORIDEOCON,
+ BS_DAGGER,
+ BS_SWORD,
+ BS_TWOHANDSWORD,
+ BS_AXE,
+ BS_MACE,
+ BS_KNUCKLE,
+ BS_SPEAR,
+ BS_HILTBINDING,
+ BS_FINDINGORE,
+ BS_WEAPONRESEARCH,
+ BS_REPAIRWEAPON,
+ BS_SKINTEMPER,
+ BS_HAMMERFALL,
+ BS_ADRENALINE,
+ BS_WEAPONPERFECT,
+ BS_OVERTHRUST,
+ BS_MAXIMIZE,
+
+ HT_SKIDTRAP,
+ HT_LANDMINE,
+ HT_ANKLESNARE,
+ HT_SHOCKWAVE,
+ HT_SANDMAN,
+ HT_FLASHER,
+ HT_FREEZINGTRAP,
+ HT_BLASTMINE,
+ HT_CLAYMORETRAP,
+ HT_REMOVETRAP,
+ HT_TALKIEBOX,
+ HT_BEASTBANE,
+ HT_FALCON,
+ HT_STEELCROW,
+ HT_BLITZBEAT,
+ HT_DETECTING,
+ HT_SPRINGTRAP,
+
+ AS_RIGHT,
+ AS_LEFT,
+ AS_KATAR,
+ AS_CLOAKING,
+ AS_SONICBLOW,
+ AS_GRIMTOOTH,
+ AS_ENCHANTPOISON,
+ AS_POISONREACT,
+ AS_VENOMDUST,
+ AS_SPLASHER,
+
+ NV_FIRSTAID,
+ NV_TRICKDEAD,
+ SM_MOVINGRECOVERY,
+ SM_FATALBLOW,
+ SM_AUTOBERSERK,
+ AC_MAKINGARROW,
+ AC_CHARGEARROW,
+ TF_SPRINKLESAND,
+ TF_BACKSLIDING,
+ TF_PICKSTONE,
+ TF_THROWSTONE,
+ MC_CARTREVOLUTION,
+ MC_CHANGECART,
+ MC_LOUD,
+ AL_HOLYLIGHT,
+ MG_ENERGYCOAT,
+
+ NPC_PIERCINGATT,
+ NPC_MENTALBREAKER,
+ NPC_RANGEATTACK,
+ NPC_ATTRICHANGE,
+ NPC_CHANGEWATER,
+ NPC_CHANGEGROUND,
+ NPC_CHANGEFIRE,
+ NPC_CHANGEWIND,
+ NPC_CHANGEPOISON,
+ NPC_CHANGEHOLY,
+ NPC_CHANGEDARKNESS,
+ NPC_CHANGETELEKINESIS,
+ NPC_CRITICALSLASH,
+ NPC_COMBOATTACK,
+ NPC_GUIDEDATTACK,
+ NPC_SELFDESTRUCTION,
+ NPC_SPLASHATTACK,
+ NPC_SUICIDE,
+ NPC_POISON,
+ NPC_BLINDATTACK,
+ NPC_SILENCEATTACK,
+ NPC_STUNATTACK,
+ NPC_PETRIFYATTACK,
+ NPC_CURSEATTACK,
+ NPC_SLEEPATTACK,
+ NPC_RANDOMATTACK,
+ NPC_WATERATTACK,
+ NPC_GROUNDATTACK,
+ NPC_FIREATTACK,
+ NPC_WINDATTACK,
+ NPC_POISONATTACK,
+ NPC_HOLYATTACK,
+ NPC_DARKNESSATTACK,
+ NPC_TELEKINESISATTACK,
+ NPC_MAGICALATTACK,
+ NPC_METAMORPHOSIS,
+ NPC_PROVOCATION,
+ NPC_SMOKING,
+ NPC_SUMMONSLAVE,
+ NPC_EMOTION,
+ NPC_TRANSFORMATION,
+ NPC_BLOODDRAIN,
+ NPC_ENERGYDRAIN,
+ NPC_KEEPING,
+ NPC_DARKBREATH,
+ NPC_DARKBLESSING,
+ NPC_BARRIER,
+ NPC_DEFENDER,
+ NPC_LICK,
+ NPC_HALLUCINATION,
+ NPC_REBIRTH,
+ NPC_SUMMONMONSTER,
+
+ RG_SNATCHER,
+ RG_STEALCOIN,
+ RG_BACKSTAP,
+ RG_TUNNELDRIVE,
+ RG_RAID,
+ RG_STRIPWEAPON,
+ RG_STRIPSHIELD,
+ RG_STRIPARMOR,
+ RG_STRIPHELM,
+ RG_INTIMIDATE,
+ RG_GRAFFITI,
+ RG_FLAGGRAFFITI,
+ RG_CLEANER,
+ RG_GANGSTER,
+ RG_COMPULSION,
+ RG_PLAGIARISM,
+
+ AM_AXEMASTERY,
+ AM_LEARNINGPOTION,
+ AM_PHARMACY,
+ AM_DEMONSTRATION,
+ AM_ACIDTERROR,
+ AM_POTIONPITCHER,
+ AM_CANNIBALIZE,
+ AM_SPHEREMINE,
+ AM_CP_WEAPON,
+ AM_CP_SHIELD,
+ AM_CP_ARMOR,
+ AM_CP_HELM,
+ AM_BIOETHICS,
+ AM_BIOTECHNOLOGY,
+ AM_CREATECREATURE,
+ AM_CULTIVATION,
+ AM_FLAMECONTROL,
+ AM_CALLHOMUN,
+ AM_REST,
+ AM_DRILLMASTER,
+ AM_HEALHOMUN,
+ AM_RESURRECTHOMUN,
+
+ CR_TRUST,
+ CR_AUTOGUARD,
+ CR_SHIELDCHARGE,
+ CR_SHIELDBOOMERANG,
+ CR_REFLECTSHIELD,
+ CR_HOLYCROSS,
+ CR_GRANDCROSS,
+ CR_DEVOTION,
+ CR_PROVIDENCE,
+ CR_DEFENDER,
+ CR_SPEARQUICKEN,
+
+ MO_IRONHAND,
+ MO_SPIRITSRECOVERY,
+ MO_CALLSPIRITS,
+ MO_ABSORBSPIRITS,
+ MO_TRIPLEATTACK,
+ MO_BODYRELOCATION,
+ MO_DODGE,
+ MO_INVESTIGATE,
+ MO_FINGEROFFENSIVE,
+ MO_STEELBODY,
+ MO_BLADESTOP,
+ MO_EXPLOSIONSPIRITS,
+ MO_EXTREMITYFIST,
+ MO_CHAINCOMBO,
+ MO_COMBOFINISH,
+
+ SA_ADVANCEDBOOK,
+ SA_CASTCANCEL,
+ SA_MAGICROD,
+ SA_SPELLBREAKER,
+ SA_FREECAST,
+ SA_AUTOSPELL,
+ SA_FLAMELAUNCHER,
+ SA_FROSTWEAPON,
+ SA_LIGHTNINGLOADER,
+ SA_SEISMICWEAPON,
+ SA_DRAGONOLOGY,
+ SA_VOLCANO,
+ SA_DELUGE,
+ SA_VIOLENTGALE,
+ SA_LANDPROTECTOR,
+ SA_DISPELL,
+ SA_ABRACADABRA,
+ SA_MONOCELL,
+ SA_CLASSCHANGE,
+ SA_SUMMONMONSTER,
+ SA_REVERSEORCISH,
+ SA_DEATH,
+ SA_FORTUNE,
+ SA_TAMINGMONSTER,
+ SA_QUESTION,
+ SA_GRAVITY,
+ SA_LEVELUP,
+ SA_INSTANTDEATH,
+ SA_FULLRECOVERY,
+ SA_COMA,
+
+ BD_ADAPTATION,
+ BD_ENCORE,
+ BD_LULLABY,
+ BD_RICHMANKIM,
+ BD_ETERNALCHAOS,
+ BD_DRUMBATTLEFIELD,
+ BD_RINGNIBELUNGEN,
+ BD_ROKISWEIL,
+ BD_INTOABYSS,
+ BD_SIEGFRIED,
+ BD_RAGNAROK,
+
+ BA_MUSICALLESSON,
+ BA_MUSICALSTRIKE,
+ BA_DISSONANCE,
+ BA_FROSTJOKE,
+ BA_WHISTLE,
+ BA_ASSASSINCROSS,
+ BA_POEMBRAGI,
+ BA_APPLEIDUN,
+
+ DC_DANCINGLESSON,
+ DC_THROWARROW,
+ DC_UGLYDANCE,
+ DC_SCREAM,
+ DC_HUMMING,
+ DC_DONTFORGETME,
+ DC_FORTUNEKISS,
+ DC_SERVICEFORYOU,
+
+ WE_MALE = 334,
+ WE_FEMALE,
+ WE_CALLPARTNER,
+
+ NPC_SELFDESTRUCTION2 = 331,
+ NPC_DARKCROSS = 338,
+
+ LK_AURABLADE = 355,
+ LK_PARRYING,
+ LK_CONCENTRATION,
+ LK_TENSIONRELAX,
+ LK_BERSERK,
+ LK_FURY,
+ HP_ASSUMPTIO,
+ HP_BASILICA,
+ HP_MEDITATIO,
+ HW_SOULDRAIN,
+ HW_MAGICCRASHER,
+ HW_MAGICPOWER,
+ PA_PRESSURE,
+ PA_SACRIFICE,
+ PA_GOSPEL,
+ CH_PALMSTRIKE,
+ CH_TIGERFIST,
+ CH_CHAINCRUSH,
+ PF_HPCONVERSION,
+ PF_SOULCHANGE,
+ PF_SOULBURN,
+ ASC_KATAR,
+ ASC_HALLUCINATION,
+ ASC_EDP,
+ ASC_BREAKER,
+ SN_SIGHT,
+ SN_FALCONASSAULT,
+ SN_SHARPSHOOTING,
+ SN_WINDWALK,
+ WS_MELTDOWN,
+ WS_CREATECOIN,
+ WS_CREATENUGGET,
+ WS_CARTBOOST,
+ WS_SYSTEMCREATE,
+ ST_CHASEWALK,
+ ST_REJECTSWORD,
+ ST_STEALBACKPACK,
+ CR_ALCHEMY,
+ CR_SYNTHESISPOTION,
+ CG_ARROWVULCAN,
+ CG_MOONLIT,
+ CG_MARIONETTE,
+ LK_SPIRALPIERCE,
+ LK_HEADCRUSH,
+ LK_JOINTBEAT,
+ HW_NAPALMVULCAN,
+ CH_SOULCOLLECT,
+ PF_MINDBREAKER,
+ PF_MEMORIZE,
+ PF_FOGWALL,
+ PF_SPIDERWEB,
+ ASC_METEORASSAULT,
+ ASC_CDP,
+ WE_BABY,
+ WE_CALLPARENT,
+ WE_CALLBABY,
+ TK_RUN,
+ TK_READYSTORM,
+ TK_STORMKICK,
+ TK_READYDOWN,
+ TK_DOWNKICK,
+ TK_READYTURN,
+ TK_TURNKICK,
+ TK_READYCOUNTER,
+ TK_COUNTER,
+ TK_DODGE,
+ TK_JUMPKICK,
+ TK_HPTIME,
+ TK_SPTIME,
+ TK_POWER,
+ TK_SEVENWIND,
+ TK_HIGHJUMP,
+ SG_FEEL,
+ SG_SUN_WARM,
+ SG_MOON_WARM,
+ SG_STAR_WARM,
+ SG_SUN_COMFORT,
+ SG_MOON_COMFORT,
+ SG_STAR_COMFORT,
+ SG_HATE,
+ SG_SUN_ANGER,
+ SG_MOON_ANGER,
+ SG_STAR_ANGER,
+ SG_SUN_BLESS,
+ SG_MOON_BLESS,
+ SG_STAR_BLESS,
+ SG_DEVIL,
+ SG_FRIEND,
+ SG_KNOWLEDGE,
+ SG_FUSION,
+ SL_ALCHEMIST,
+ AM_BERSERKPITCHER,
+ SL_MONK,
+ SL_STAR,
+ SL_SAGE,
+ SL_CRUSADER,
+ SL_SUPERNOVICE,
+ SL_KNIGHT,
+ SL_WIZARD,
+ SL_PRIEST,
+ SL_BARDDANCER,
+ SL_ROGUE,
+ SL_ASSASIN,
+ SL_BLACKSMITH,
+ BS_ADRENALINE2,
+ SL_HUNTER,
+ SL_SOULLINKER,
+ SL_KAIZEL,
+ SL_KAAHI,
+ SL_KAUPE,
+ SL_KAITE,
+ SL_KAINA,
+ SL_STIN,
+ SL_STUN,
+ SL_SMA,
+ SL_SWOO,
+ SL_SKE,
+ SL_SKA,
+
+ GD_APPROVAL=10000,
+ GD_KAFRACONTACT=10001,
+ GD_GUARDIANRESEARCH=10002,
+ GD_CHARISMA=10003,
+ GD_GUARDUP=10003,
+ GD_EXTENSION=10004,
+ GD_GLORYGUILD=10005,
+ GD_LEADERSHIP=10006,
+ GD_GLORYWOUNDS=10007,
+ GD_SOULCOLD=10008,
+ GD_HAWKEYES=10009,
+ GD_BATTLEORDER=10010,
+ GD_REGENERATION=10011,
+ GD_RESTORE=10012,
+ GD_EMERGENCYCALL=10013,
+ GD_DEVELOPMENT=10014,
+};
+
+#endif
+
diff --git a/src/map/storage.c b/src/map/storage.c
new file mode 100644
index 000000000..b10b73bb0
--- /dev/null
+++ b/src/map/storage.c
@@ -0,0 +1,595 @@
+// $Id: storage.c,v 1.3 2004/09/25 02:05:22 MouseJstr Exp $
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db.h"
+#include "itemdb.h"
+#include "clif.h"
+#include "intif.h"
+#include "pc.h"
+#include "storage.h"
+#include "guild.h"
+#include "nullpo.h"
+
+#ifdef MEMWATCH
+#include "memwatch.h"
+#endif
+
+static struct dbt *storage_db;
+static struct dbt *guild_storage_db;
+
+/*==========================================
+ * 倉庫内アイテムソート
+ *------------------------------------------
+ */
+int storage_comp_item(const void *_i1, const void *_i2){
+struct item *i1=(struct item *)_i1;
+struct item *i2=(struct item *)_i2;
+
+ if (i1->nameid == i2->nameid) {
+ return 0;
+ } else if (!(i1->nameid) || !(i1->amount)){
+ return 1;
+ } else if (!(i2->nameid) || !(i2->amount)){
+ return -1;
+ } else {
+ return i1->nameid - i2->nameid;
+ }
+}
+
+
+void sortage_sortitem(struct storage* stor){
+ nullpo_retv(stor);
+
+ qsort(stor->storage, MAX_STORAGE, sizeof(struct item), storage_comp_item);
+}
+
+void sortage_gsortitem(struct guild_storage* gstor){
+ nullpo_retv(gstor);
+
+ qsort(gstor->storage, MAX_GUILD_STORAGE, sizeof(struct item), storage_comp_item);
+}
+
+/*==========================================
+ * 初期化とか
+ *------------------------------------------
+ */
+int do_init_storage(void) // map.c::do_init()から呼ばれる
+{
+ storage_db=numdb_init();
+ guild_storage_db=numdb_init();
+ return 1;
+}
+
+void do_final_storage(void) // map.c::do_final()から呼ばれる
+{
+}
+
+struct storage *account2storage(int account_id)
+{
+ struct storage *stor;
+ stor=numdb_search(storage_db,account_id);
+ if(stor == NULL) {
+ stor = calloc(sizeof(struct storage), 1);
+ if(stor == NULL){
+ printf("storage: out of memory!\n");
+ exit(0);
+ }
+ memset(stor,0,sizeof(struct storage));
+ stor->account_id=account_id;
+ numdb_insert(storage_db,stor->account_id,stor);
+ }
+ return stor;
+}
+
+// Just to ask storage, without creation
+struct storage *account2storage2(int account_id) {
+ return numdb_search(storage_db, account_id);
+}
+
+int storage_delete(int account_id)
+{
+ struct storage *stor = numdb_search(storage_db,account_id);
+ if(stor) {
+ numdb_erase(storage_db,account_id);
+ free(stor);
+ }
+ return 0;
+}
+
+/*==========================================
+ * カプラ倉庫を開く
+ *------------------------------------------
+ */
+int storage_storageopen(struct map_session_data *sd)
+{
+ struct storage *stor;
+
+ nullpo_retr(0, sd);
+
+ if((stor = numdb_search(storage_db,sd->status.account_id)) != NULL) {
+ stor->storage_status = 1;
+ sd->state.storage_flag = 0;
+ clif_storageitemlist(sd,stor);
+ clif_storageequiplist(sd,stor);
+ clif_updatestorageamount(sd,stor);
+ return 0;
+ } else
+ intif_request_storage(sd->status.account_id);
+
+ return 1;
+}
+
+int storage_storageopen2(struct map_session_data *sd, struct map_session_data *pl_sd)
+{
+ struct storage *stor;
+ if(sd == NULL || pl_sd == NULL)
+ {
+ printf("storage_storageopen nullpo\n");
+ return 0;
+ }
+
+ if((stor = numdb_search(storage_db,pl_sd->status.account_id)) != NULL)
+ {
+ clif_storageitemlist(sd,stor);
+ clif_storageequiplist(sd,stor);
+ clif_updatestorageamount(sd,stor);
+ return 1;
+ }
+ return 0;
+}
+
+/*==========================================
+ * カプラ倉庫へアイテム追加
+ *------------------------------------------
+ */
+int storage_additem(struct map_session_data *sd,struct storage *stor,struct item *item_data,int amount)
+{
+ struct item_data *data;
+ int i;
+
+ nullpo_retr(1, sd);
+ nullpo_retr(1, stor);
+ nullpo_retr(1, item_data);
+
+ if(item_data->nameid <= 0 || amount <= 0)
+ return 1;
+ nullpo_retr(1, data = itemdb_search(item_data->nameid));
+
+ i=MAX_STORAGE;
+ if(!itemdb_isequip2(data)){
+ // 装備品ではないので、既所有品なら個数のみ変化させる
+ for(i=0;i<MAX_STORAGE;i++){
+ if(stor->storage[i].nameid == item_data->nameid &&
+ stor->storage[i].card[0] == item_data->card[0] && stor->storage[i].card[1] == item_data->card[1] &&
+ stor->storage[i].card[2] == item_data->card[2] && stor->storage[i].card[3] == item_data->card[3]){
+ if(stor->storage[i].amount+amount > MAX_AMOUNT)
+ return 1;
+ stor->storage[i].amount+=amount;
+ clif_storageitemadded(sd,stor,i,amount);
+ break;
+ }
+ }
+ }
+ if(i>=MAX_STORAGE){
+ // 装備品か未所有品だったので空き欄へ追加
+ for(i=0;i<MAX_STORAGE;i++){
+ if(stor->storage[i].nameid==0){
+ memcpy(&stor->storage[i],item_data,sizeof(stor->storage[0]));
+ stor->storage[i].amount=amount;
+ stor->storage_amount++;
+ clif_storageitemadded(sd,stor,i,amount);
+ clif_updatestorageamount(sd,stor);
+ break;
+ }
+ }
+ if(i>=MAX_STORAGE)
+ return 1;
+ }
+ return 0;
+}
+/*==========================================
+ * カプラ倉庫アイテムを減らす
+ *------------------------------------------
+ */
+int storage_delitem(struct map_session_data *sd,struct storage *stor,int n,int amount)
+{
+ nullpo_retr(1, sd);
+ nullpo_retr(1, stor);
+
+ if(stor->storage[n].nameid==0 || stor->storage[n].amount<amount)
+ return 1;
+
+ stor->storage[n].amount-=amount;
+ if(stor->storage[n].amount==0){
+ memset(&stor->storage[n],0,sizeof(stor->storage[0]));
+ stor->storage_amount--;
+ clif_updatestorageamount(sd,stor);
+ }
+ clif_storageitemremoved(sd,n,amount);
+
+ return 0;
+}
+/*==========================================
+ * カプラ倉庫へ入れる
+ *------------------------------------------
+ */
+int storage_storageadd(struct map_session_data *sd,int index,int amount)
+{
+ struct storage *stor;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor=account2storage(sd->status.account_id));
+
+ if( (stor->storage_amount <= MAX_STORAGE) && (stor->storage_status == 1) ) { // storage not full & storage open
+ if(index>=0 && index<MAX_INVENTORY) { // valid index
+ if( (amount <= sd->status.inventory[index].amount) && (amount > 0) ) { //valid amount
+ if(storage_additem(sd,stor,&sd->status.inventory[index],amount)==0)
+ // remove item from inventory
+ pc_delitem(sd,index,amount,0);
+ } // valid amount
+ }// valid index
+ }// storage not full & storage open
+
+ return 0;
+}
+
+/*==========================================
+ * カプラ倉庫から出す
+ *------------------------------------------
+ */
+int storage_storageget(struct map_session_data *sd,int index,int amount)
+{
+ struct storage *stor;
+ int flag;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor=account2storage(sd->status.account_id));
+
+ if(stor->storage_status == 1) { // storage open
+ if(index>=0 && index<MAX_STORAGE) { // valid index
+ if( (amount <= stor->storage[index].amount) && (amount > 0) ) { //valid amount
+ if((flag = pc_additem(sd,&stor->storage[index],amount)) == 0)
+ storage_delitem(sd,stor,index,amount);
+ else
+ clif_additem(sd,0,0,flag);
+ } // valid amount
+ }// valid index
+ }// storage open
+
+ return 0;
+}
+/*==========================================
+ * カプラ倉庫へカートから入れる
+ *------------------------------------------
+ */
+int storage_storageaddfromcart(struct map_session_data *sd,int index,int amount)
+{
+ struct storage *stor;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor=account2storage(sd->status.account_id));
+
+ if( (stor->storage_amount <= MAX_STORAGE) && (stor->storage_status == 1) ) { // storage not full & storage open
+ if(index>=0 && index<MAX_INVENTORY) { // valid index
+ if( (amount <= sd->status.cart[index].amount) && (amount > 0) ) { //valid amount
+ if(storage_additem(sd,stor,&sd->status.cart[index],amount)==0)
+ pc_cart_delitem(sd,index,amount,0);
+ } // valid amount
+ }// valid index
+ }// storage not full & storage open
+
+ return 0;
+}
+
+/*==========================================
+ * カプラ倉庫からカートへ出す
+ *------------------------------------------
+ */
+int storage_storagegettocart(struct map_session_data *sd,int index,int amount)
+{
+ struct storage *stor;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor=account2storage(sd->status.account_id));
+
+ if(stor->storage_status == 1) { // storage open
+ if(index>=0 && index<MAX_STORAGE) { // valid index
+ if( (amount <= stor->storage[index].amount) && (amount > 0) ) { //valid amount
+ if(pc_cart_additem(sd,&stor->storage[index],amount)==0){
+ storage_delitem(sd,stor,index,amount);
+ }
+ } // valid amount
+ }// valid index
+ }// storage open
+
+ return 0;
+}
+
+
+/*==========================================
+ * カプラ倉庫を閉じる
+ *------------------------------------------
+ */
+int storage_storageclose(struct map_session_data *sd)
+{
+ struct storage *stor;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor=account2storage(sd->status.account_id));
+
+ stor->storage_status=0;
+ sd->state.storage_flag = 0;
+ clif_storageclose(sd);
+
+ sortage_sortitem(stor);
+ return 0;
+}
+
+/*==========================================
+ * ログアウト時開いているカプラ倉庫の保存
+ *------------------------------------------
+ */
+int storage_storage_quit(struct map_session_data *sd)
+{
+ struct storage *stor;
+
+ nullpo_retr(0, sd);
+
+ stor = numdb_search(storage_db,sd->status.account_id);
+ if(stor) stor->storage_status = 0;
+
+ return 0;
+}
+
+int storage_storage_save(struct map_session_data *sd)
+{
+ struct storage *stor;
+
+ nullpo_retr(0, sd);
+
+ stor=numdb_search(storage_db,sd->status.account_id);
+ if(stor) intif_send_storage(stor);
+
+ return 0;
+}
+
+struct guild_storage *guild2storage(int guild_id)
+{
+ struct guild_storage *gs = NULL;
+ if(guild_search(guild_id) != NULL) {
+ gs=numdb_search(guild_storage_db,guild_id);
+ if(gs == NULL) {
+ gs = calloc(sizeof(struct guild_storage), 1);
+ if(gs==NULL){
+ printf("storage: out of memory!\n");
+ exit(0);
+ }
+ gs->guild_id=guild_id;
+ numdb_insert(guild_storage_db,gs->guild_id,gs);
+ }
+ }
+ return gs;
+}
+
+int guild_storage_delete(int guild_id)
+{
+ struct guild_storage *gstor = numdb_search(guild_storage_db,guild_id);
+ if(gstor) {
+ numdb_erase(guild_storage_db,guild_id);
+ free(gstor);
+ }
+ return 0;
+}
+
+int storage_guild_storageopen(struct map_session_data *sd)
+{
+ struct guild_storage *gstor;
+
+ nullpo_retr(0, sd);
+
+ if(sd->status.guild_id <= 0)
+ return 2;
+ if((gstor = numdb_search(guild_storage_db,sd->status.guild_id)) != NULL) {
+ if(gstor->storage_status)
+ return 1;
+ gstor->storage_status = 1;
+ sd->state.storage_flag = 1;
+ clif_guildstorageitemlist(sd,gstor);
+ clif_guildstorageequiplist(sd,gstor);
+ clif_updateguildstorageamount(sd,gstor);
+ return 0;
+ }
+ else {
+ gstor = guild2storage(sd->status.guild_id);
+ gstor->storage_status = 1;
+ intif_request_guild_storage(sd->status.account_id,sd->status.guild_id);
+ }
+
+ return 0;
+}
+
+int guild_storage_additem(struct map_session_data *sd,struct guild_storage *stor,struct item *item_data,int amount)
+{
+ struct item_data *data;
+ int i;
+
+ nullpo_retr(1, sd);
+ nullpo_retr(1, stor);
+ nullpo_retr(1, item_data);
+ nullpo_retr(1, data = itemdb_search(item_data->nameid));
+
+ if(item_data->nameid <= 0 || amount <= 0)
+ return 1;
+
+ i=MAX_GUILD_STORAGE;
+ if(!itemdb_isequip2(data)){
+ // 装備品ではないので、既所有品なら個数のみ変化させる
+ for(i=0;i<MAX_GUILD_STORAGE;i++){
+ if(stor->storage[i].nameid == item_data->nameid &&
+ stor->storage[i].card[0] == item_data->card[0] && stor->storage[i].card[1] == item_data->card[1] &&
+ stor->storage[i].card[2] == item_data->card[2] && stor->storage[i].card[3] == item_data->card[3]){
+ if(stor->storage[i].amount+amount > MAX_AMOUNT)
+ return 1;
+ stor->storage[i].amount+=amount;
+ clif_guildstorageitemadded(sd,stor,i,amount);
+ break;
+ }
+ }
+ }
+ if(i>=MAX_GUILD_STORAGE){
+ // 装備品か未所有品だったので空き欄へ追加
+ for(i=0;i<MAX_GUILD_STORAGE;i++){
+ if(stor->storage[i].nameid==0){
+ memcpy(&stor->storage[i],item_data,sizeof(stor->storage[0]));
+ stor->storage[i].amount=amount;
+ stor->storage_amount++;
+ clif_guildstorageitemadded(sd,stor,i,amount);
+ clif_updateguildstorageamount(sd,stor);
+ break;
+ }
+ }
+ if(i>=MAX_GUILD_STORAGE)
+ return 1;
+ }
+ return 0;
+}
+
+int guild_storage_delitem(struct map_session_data *sd,struct guild_storage *stor,int n,int amount)
+{
+ nullpo_retr(1, sd);
+ nullpo_retr(1, stor);
+
+ if(stor->storage[n].nameid==0 || stor->storage[n].amount<amount)
+ return 1;
+
+ stor->storage[n].amount-=amount;
+ if(stor->storage[n].amount==0){
+ memset(&stor->storage[n],0,sizeof(stor->storage[0]));
+ stor->storage_amount--;
+ clif_updateguildstorageamount(sd,stor);
+ }
+ clif_storageitemremoved(sd,n,amount);
+
+ return 0;
+}
+
+int storage_guild_storageadd(struct map_session_data *sd,int index,int amount)
+{
+ struct guild_storage *stor;
+
+ nullpo_retr(0, sd);
+
+ if((stor=guild2storage(sd->status.guild_id)) != NULL) {
+ if( (stor->storage_amount <= MAX_GUILD_STORAGE) && (stor->storage_status == 1) ) { // storage not full & storage open
+ if(index>=0 && index<MAX_INVENTORY) { // valid index
+ if( (amount <= sd->status.inventory[index].amount) && (amount > 0) ) { //valid amount
+ if(guild_storage_additem(sd,stor,&sd->status.inventory[index],amount)==0)
+ // remove item from inventory
+ pc_delitem(sd,index,amount,0);
+ } // valid amount
+ }// valid index
+ }// storage not full & storage open
+ }
+
+ return 0;
+}
+
+int storage_guild_storageget(struct map_session_data *sd,int index,int amount)
+{
+ struct guild_storage *stor;
+ int flag;
+
+ nullpo_retr(0, sd);
+
+ if((stor=guild2storage(sd->status.guild_id)) != NULL) {
+ if(stor->storage_status == 1) { // storage open
+ if(index>=0 && index<MAX_GUILD_STORAGE) { // valid index
+ if( (amount <= stor->storage[index].amount) && (amount > 0) ) { //valid amount
+ if((flag = pc_additem(sd,&stor->storage[index],amount)) == 0)
+ guild_storage_delitem(sd,stor,index,amount);
+ else
+ clif_additem(sd,0,0,flag);
+ } // valid amount
+ }// valid index
+ }// storage open
+ }
+
+ return 0;
+}
+
+int storage_guild_storageaddfromcart(struct map_session_data *sd,int index,int amount)
+{
+ struct guild_storage *stor;
+
+ nullpo_retr(0, sd);
+
+ if((stor=guild2storage(sd->status.guild_id)) != NULL) {
+ if( (stor->storage_amount <= MAX_GUILD_STORAGE) && (stor->storage_status == 1) ) { // storage not full & storage open
+ if(index>=0 && index<MAX_INVENTORY) { // valid index
+ if( (amount <= sd->status.cart[index].amount) && (amount > 0) ) { //valid amount
+ if(guild_storage_additem(sd,stor,&sd->status.cart[index],amount)==0)
+ pc_cart_delitem(sd,index,amount,0);
+ } // valid amount
+ }// valid index
+ }// storage not full & storage open
+ }
+
+ return 0;
+}
+
+int storage_guild_storagegettocart(struct map_session_data *sd,int index,int amount)
+{
+ struct guild_storage *stor;
+
+ nullpo_retr(0, sd);
+
+ if((stor=guild2storage(sd->status.guild_id)) != NULL) {
+ if(stor->storage_status == 1) { // storage open
+ if(index>=0 && index<MAX_GUILD_STORAGE) { // valid index
+ if( (amount <= stor->storage[index].amount) && (amount > 0) ) { //valid amount
+ if(pc_cart_additem(sd,&stor->storage[index],amount)==0){
+ guild_storage_delitem(sd,stor,index,amount);
+ }
+ } // valid amount
+ }// valid index
+ }// storage open
+ }
+
+ return 0;
+}
+
+int storage_guild_storageclose(struct map_session_data *sd)
+{
+ struct guild_storage *stor;
+
+ nullpo_retr(0, sd);
+
+ if((stor=guild2storage(sd->status.guild_id)) != NULL) {
+ intif_send_guild_storage(sd->status.account_id,stor);
+ stor->storage_status = 0;
+ sd->state.storage_flag = 0;
+ sortage_gsortitem(stor);
+ }
+ clif_storageclose(sd);
+
+ return 0;
+}
+
+int storage_guild_storage_quit(struct map_session_data *sd,int flag)
+{
+ struct guild_storage *stor;
+
+ nullpo_retr(0, sd);
+
+ stor = numdb_search(guild_storage_db,sd->status.guild_id);
+ if(stor) {
+ if(!flag)
+ intif_send_guild_storage(sd->status.account_id,stor);
+ stor->storage_status = 0;
+ sd->state.storage_flag = 0;
+ }
+
+ return 0;
+}
diff --git a/src/map/storage.h b/src/map/storage.h
new file mode 100644
index 000000000..4e89e657a
--- /dev/null
+++ b/src/map/storage.h
@@ -0,0 +1,39 @@
+// $Id: storage.h,v 1.3 2004/09/25 05:32:19 MouseJstr Exp $
+#ifndef _STORAGE_H_
+#define _STORAGE_H_
+
+#include "mmo.h"
+
+int storage_storageopen(struct map_session_data *sd);
+int storage_storageopen2(struct map_session_data *sd,struct map_session_data *pl_sd);
+int storage_storageadd(struct map_session_data *sd,int index,int amount);
+int storage_storageget(struct map_session_data *sd,int index,int amount);
+int storage_storageaddfromcart(struct map_session_data *sd,int index,int amount);
+int storage_storagegettocart(struct map_session_data *sd,int index,int amount);
+int storage_storageclose(struct map_session_data *sd);
+int do_init_storage(void);
+void do_final_storage(void);
+struct storage *account2storage(int account_id);
+struct storage *account2storage2(int account_id);
+int storage_delete(int account_id);
+int storage_storage_quit(struct map_session_data *sd);
+int storage_storage_save(struct map_session_data *sd);
+
+struct guild_storage *guild2storage(int guild_id);
+int guild_storage_delete(int guild_id);
+int storage_guild_storageopen(struct map_session_data *sd);
+int guild_storage_additem(struct map_session_data *sd,struct guild_storage *stor,struct item *item_data,int amount);
+int guild_storage_delitem(struct map_session_data *sd,struct guild_storage *stor,int n,int amount);
+int storage_guild_storageadd(struct map_session_data *sd,int index,int amount);
+int storage_guild_storageget(struct map_session_data *sd,int index,int amount);
+int storage_guild_storageaddfromcart(struct map_session_data *sd,int index,int amount);
+int storage_guild_storagegettocart(struct map_session_data *sd,int index,int amount);
+int storage_guild_storageclose(struct map_session_data *sd);
+int storage_guild_storage_quit(struct map_session_data *sd,int flag);
+
+int storage_comp_item(const void *_i1, const void *_i2);
+//int storage_comp_item(const struct item* i1, const struct item* i2);
+void sortage_sortitem(struct storage* stor);
+void sortage_gsortitem(struct guild_storage* gstor);
+
+#endif
diff --git a/src/map/trade.c b/src/map/trade.c
new file mode 100644
index 000000000..41a89cd7a
--- /dev/null
+++ b/src/map/trade.c
@@ -0,0 +1,286 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "clif.h"
+#include "itemdb.h"
+#include "map.h"
+#include "trade.h"
+#include "pc.h"
+#include "npc.h"
+#include "battle.h"
+#include "nullpo.h"
+#include "log.h"
+
+/*==========================================
+ * 取引要請を相手に送る
+ *------------------------------------------
+ */
+void trade_traderequest(struct map_session_data *sd,int target_id)
+{
+ struct map_session_data *target_sd;
+
+ nullpo_retv(sd);
+
+ if((target_sd = map_id2sd(target_id)) != NULL){
+ if(!battle_config.invite_request_check) {
+ if(target_sd->guild_invite>0 || target_sd->party_invite>0){
+ clif_tradestart(sd,2); // 相手はPT要請中かGuild要請中
+ return;
+ }
+ }
+ if((target_sd->trade_partner !=0) || (sd->trade_partner !=0)) {
+ trade_tradecancel(sd); //person is in another trade
+ }
+ else{
+ if((pc_isGM(sd) < 60) && (sd->bl.m != target_sd->bl.m
+ || (sd->bl.x - target_sd->bl.x <= -5 || sd->bl.x - target_sd->bl.x >= 5)
+ || (sd->bl.y - target_sd->bl.y <= -5 || sd->bl.y - target_sd->bl.y >= 5))) {
+ clif_tradestart(sd,0); //too far
+ }
+ else if(sd!=target_sd) {
+ target_sd->trade_partner = sd->status.account_id;
+ sd->trade_partner = target_sd->status.account_id;
+ clif_traderequest(target_sd,sd->status.name);
+ }
+ }
+ }
+ else{
+ clif_tradestart(sd,1); //character does not exist
+ }
+}
+
+/*==========================================
+ * 取引要請
+ *------------------------------------------
+ */
+void trade_tradeack(struct map_session_data *sd,int type)
+{
+ struct map_session_data *target_sd;
+
+ nullpo_retv(sd);
+
+ if((target_sd = map_id2sd(sd->trade_partner)) != NULL){
+ clif_tradestart(target_sd,type);
+ clif_tradestart(sd,type);
+ if(type == 4){ // Cancel
+ sd->deal_locked =0;
+ sd->trade_partner=0;
+ target_sd->deal_locked=0;
+ target_sd->trade_partner=0;
+ }
+ if(sd->npc_id != 0)
+ npc_event_dequeue(sd);
+ if(target_sd->npc_id != 0)
+ npc_event_dequeue(target_sd);
+ }
+}
+
+/*==========================================
+ * アイテム追加
+ *------------------------------------------
+ */
+void trade_tradeadditem(struct map_session_data *sd,int index,int amount)
+{
+ struct map_session_data *target_sd;
+ int trade_i;
+ int trade_weight=0;
+ int c;
+
+ nullpo_retv(sd);
+
+ if(((target_sd = map_id2sd(sd->trade_partner)) != NULL) && (sd->deal_locked < 1)){
+ if(index<2 || index>=MAX_INVENTORY+2){
+ if(index == 0 && amount > 0 && amount <= sd->status.zeny){
+ sd->deal_zeny=amount;
+ clif_tradeadditem(sd,target_sd,0,amount);
+ }
+ }else if(amount <= sd->status.inventory[index-2].amount && amount > 0){
+ for(trade_i=0; trade_i<10;trade_i++){
+ if(sd->deal_item_amount[trade_i] == 0){
+ trade_weight+=sd->inventory_data[index-2]->weight*amount;
+ if(target_sd->weight + trade_weight > target_sd->max_weight){
+ clif_tradeitemok(sd,index,1); //fail to add item -- the player was over weighted.
+ amount = 0; // [MouseJstr]
+ }else{
+ for(c=0; c==trade_i-1;c++){ // re-deal exploit protection [Valaris]
+ if(sd->deal_item_index[c]==index) {
+ trade_tradecancel(sd);
+ return;
+ }
+ }
+ sd->deal_item_index[trade_i] =index;
+ sd->deal_item_amount[trade_i]+=amount;
+ clif_tradeitemok(sd,index,0); //success to add item
+ clif_tradeadditem(sd,target_sd,index,amount);
+ }
+ break;
+ }else{
+ trade_weight+=sd->inventory_data[sd->deal_item_index[trade_i]-2]->weight*sd->deal_item_amount[trade_i];
+ }
+ }
+ }
+ }
+}
+
+/*==========================================
+ * アイテム追加完了(ok押し)
+ *------------------------------------------
+ */
+void trade_tradeok(struct map_session_data *sd)
+{
+ struct map_session_data *target_sd;
+ int trade_i;
+
+ nullpo_retv(sd);
+
+ for(trade_i=0;trade_i<10;trade_i++) {
+ if(sd->deal_item_amount[trade_i]>sd->status.inventory[sd->deal_item_index[trade_i]-2].amount ||
+ sd->deal_item_amount[trade_i]<0) {
+ trade_tradecancel(sd);
+ return;
+ }
+
+ }
+
+ if((target_sd = map_id2sd(sd->trade_partner)) != NULL){
+ sd->deal_locked=1;
+ clif_tradeitemok(sd,0,0);
+ clif_tradedeal_lock(sd,0);
+ clif_tradedeal_lock(target_sd,1);
+ }
+}
+
+/*==========================================
+ * 取引キャンセル
+ *------------------------------------------
+ */
+void trade_tradecancel(struct map_session_data *sd)
+{
+ struct map_session_data *target_sd;
+ int trade_i;
+
+ nullpo_retv(sd);
+
+ if((target_sd = map_id2sd(sd->trade_partner)) != NULL){
+ for(trade_i=0; trade_i<10;trade_i++) { //give items back (only virtual)
+ if(sd->deal_item_amount[trade_i] != 0) {
+ clif_additem(sd,sd->deal_item_index[trade_i]-2,sd->deal_item_amount[trade_i],0);
+ sd->deal_item_index[trade_i] =0;
+ sd->deal_item_amount[trade_i]=0;
+ }
+ if(target_sd->deal_item_amount[trade_i] != 0) {
+ clif_additem(target_sd,target_sd->deal_item_index[trade_i]-2,target_sd->deal_item_amount[trade_i],0);
+ target_sd->deal_item_index[trade_i] =0;
+ target_sd->deal_item_amount[trade_i]=0;
+ }
+ }
+ if(sd->deal_zeny) {
+ clif_updatestatus(sd,SP_ZENY);
+ sd->deal_zeny=0;
+ }
+ if(target_sd->deal_zeny) {
+ clif_updatestatus(target_sd,SP_ZENY);
+ target_sd->deal_zeny=0;
+ }
+ sd->deal_locked =0;
+ sd->trade_partner=0;
+ target_sd->deal_locked=0;
+ target_sd->trade_partner=0;
+ clif_tradecancelled(sd);
+ clif_tradecancelled(target_sd);
+ }
+}
+
+/*==========================================
+ * 取引許諾(trade押し)
+ *------------------------------------------
+ */
+void trade_tradecommit(struct map_session_data *sd)
+{
+ struct map_session_data *target_sd;
+ int trade_i;
+
+ nullpo_retv(sd);
+
+ if((target_sd = map_id2sd(sd->trade_partner)) != NULL){
+ if( (sd->deal_locked >=1) && (target_sd->deal_locked >=1) ){ // both have pressed 'ok'
+ if(sd->deal_locked < 2) {sd->deal_locked=2;} // set locked to 2
+ if(target_sd->deal_locked==2) { // the other one pressed 'trade' too
+ for(trade_i=0; trade_i<10;trade_i++) {
+ if(sd->deal_item_amount[trade_i] != 0) {
+ int n=sd->deal_item_index[trade_i]-2;
+ int flag;
+
+ //Dupe Fix by mark
+ if (sd->status.inventory[n].amount < sd->deal_item_amount[trade_i])
+ sd->deal_item_amount[trade_i] = sd->status.inventory[n].amount;
+ //End Dupe Fix
+
+ #ifndef TXT_ONLY
+ if(log_config.trade > 0)
+ log_trade(sd,target_sd,n,sd->deal_item_amount[trade_i]);
+ #endif //USE_SQL
+
+ flag = pc_additem(target_sd,&sd->status.inventory[n],sd->deal_item_amount[trade_i]);
+ if(flag==0)
+ pc_delitem(sd,n,sd->deal_item_amount[trade_i],1);
+ else
+ clif_additem(sd,n,sd->deal_item_amount[trade_i],0);
+ sd->deal_item_index[trade_i] =0;
+ sd->deal_item_amount[trade_i]=0;
+ }
+ if(target_sd->deal_item_amount[trade_i] != 0) {
+ int n=target_sd->deal_item_index[trade_i]-2;
+ int flag;
+
+ //Dupe Fix by mark
+ if (target_sd->status.inventory[n].amount < target_sd->deal_item_amount[trade_i])
+ target_sd->deal_item_amount[trade_i] = target_sd->status.inventory[n].amount;
+ //End Dupe Fix
+
+ #ifndef TXT_ONLY
+ if(log_config.trade > 0)
+ log_trade(target_sd,sd,n,target_sd->deal_item_amount[trade_i]);
+ #endif //USE_SQL
+
+ flag = pc_additem(sd,&target_sd->status.inventory[n],target_sd->deal_item_amount[trade_i]);
+ if(flag==0)
+ pc_delitem(target_sd,n,target_sd->deal_item_amount[trade_i],1);
+ else
+ clif_additem(target_sd,n,target_sd->deal_item_amount[trade_i],0);
+ target_sd->deal_item_index[trade_i] =0;
+ target_sd->deal_item_amount[trade_i]=0;
+ }
+ }
+ if(sd->deal_zeny) {
+ #ifndef TXT_ONLY
+ if (log_config.trade > 0 && log_config.zeny > 0)
+ log_zeny(sd, target_sd, sd->deal_zeny);
+ #endif //USE_SQL
+ sd->status.zeny -= sd->deal_zeny;
+ clif_updatestatus(sd,SP_ZENY);
+ target_sd->status.zeny += sd->deal_zeny;
+ clif_updatestatus(target_sd,SP_ZENY);
+ sd->deal_zeny=0;
+ }
+ if(target_sd->deal_zeny) {
+ #ifndef TXT_ONLY
+ if (log_config.trade > 0 && log_config.zeny > 0)
+ log_zeny(target_sd, sd, target_sd->deal_zeny);
+ #endif //USE_SQL
+ target_sd->status.zeny -= target_sd->deal_zeny;
+ clif_updatestatus(target_sd,SP_ZENY);
+ sd->status.zeny += target_sd->deal_zeny;
+ clif_updatestatus(sd,SP_ZENY);
+ target_sd->deal_zeny=0;
+ }
+ sd->deal_locked =0;
+ sd->trade_partner=0;
+ target_sd->deal_locked=0;
+ target_sd->trade_partner=0;
+ clif_tradecompleted(sd,0);
+ clif_tradecompleted(target_sd,0);
+ }
+ }
+ }
+}
diff --git a/src/map/trade.h b/src/map/trade.h
new file mode 100644
index 000000000..d796df8e6
--- /dev/null
+++ b/src/map/trade.h
@@ -0,0 +1,13 @@
+// $Id: trade.h,v 1.2 2004/09/25 05:32:19 MouseJstr Exp $
+#ifndef _TRADE_H_
+#define _TRADE_H_
+
+#include "map.h"
+void trade_traderequest(struct map_session_data *sd,int target_id);
+void trade_tradeack(struct map_session_data *sd,int type);
+void trade_tradeadditem(struct map_session_data *sd,int index,int amount);
+void trade_tradeok(struct map_session_data *sd);
+void trade_tradecancel(struct map_session_data *sd);
+void trade_tradecommit(struct map_session_data *sd);
+
+#endif // _TRADE_H_
diff --git a/src/map/vending.c b/src/map/vending.c
new file mode 100644
index 000000000..703b1b9b9
--- /dev/null
+++ b/src/map/vending.c
@@ -0,0 +1,170 @@
+// $Id: vending.c,v 1.2 2004/09/25 05:32:19 MouseJstr Exp $
+#include <stdio.h>
+#include <string.h>
+
+#include "clif.h"
+#include "itemdb.h"
+#include "map.h"
+#include "vending.h"
+#include "pc.h"
+#include "skill.h"
+#include "battle.h"
+#include "nullpo.h"
+#include "log.h"
+
+/*==========================================
+ * 露店閉鎖
+ *------------------------------------------
+*/
+void vending_closevending(struct map_session_data *sd)
+{
+
+ nullpo_retv(sd);
+
+ sd->vender_id=0;
+ clif_closevendingboard(&sd->bl,0);
+}
+
+/*==========================================
+ * 露店アイテムリスト要求
+ *------------------------------------------
+ */
+void vending_vendinglistreq(struct map_session_data *sd,int id)
+{
+ struct map_session_data *vsd;
+
+ nullpo_retv(sd);
+
+ if( (vsd=map_id2sd(id)) == NULL )
+ return;
+ if(vsd->vender_id==0)
+ return;
+ clif_vendinglist(sd,id,vsd->vending);
+}
+
+/*==========================================
+ * 露店アイテム購入
+ *------------------------------------------
+ */
+void vending_purchasereq(struct map_session_data *sd,int len,int id,unsigned char *p)
+{
+ int i,j,w,z,new=0,blank,vend_list[12];
+ short amount,index;
+ struct map_session_data *vsd=map_id2sd(id);
+
+ nullpo_retv(sd);
+
+ blank=pc_inventoryblank(sd);
+
+ if(vsd==NULL)
+ return;
+ if(vsd->vender_id==0)
+ return;
+ if(vsd->vender_id==sd->bl.id)
+ return;
+ for(i=0,w=z=0;8+4*i<len;i++){
+ amount=*(short*)(p+4*i);
+ index=*(short*)(p+2+4*i)-2;
+/*
+ if(amount < 0) return; //add
+ for(j=0;j<vsd->vend_num;j++)
+ if(0<vsd->vending[j].amount && amount<=vsd->vending[j].amount && vsd->vending[j].index==index)
+ break;
+*/
+//ADD_start
+ for(j=0;j < vsd->vend_num;j++) {
+ if(0 < vsd->vending[j].amount && vsd->vending[j].index==index) {
+ if(amount > vsd->vending[j].amount || amount <= 0) {
+ clif_buyvending(sd,index,vsd->vending[j].amount,4);
+ return;
+ }
+ if(amount <= vsd->vending[j].amount) break;
+ }
+ }
+//ADD_end
+ if(j==vsd->vend_num)
+ return; // 売り切れ
+ vend_list[i]=j;
+ z+=vsd->vending[j].value*amount;
+ if(z > sd->status.zeny){
+ clif_buyvending(sd,index,amount,1);
+ return; // zeny不足
+ }
+ w+=itemdb_weight(vsd->status.cart[index].nameid)*amount;
+ if(w+sd->weight > sd->max_weight){
+ clif_buyvending(sd,index,amount,2);
+ return; // 重量超過
+ }
+ switch(pc_checkadditem(sd,vsd->status.cart[index].nameid,amount)){
+ case ADDITEM_EXIST:
+ break;
+ case ADDITEM_NEW:
+ new++;
+ if(new > blank)
+ return; // 種類数超過
+ break;
+ case ADDITEM_OVERAMOUNT:
+ return; // アイテム数超過
+ }
+ }
+ if(z < 0 || z > MAX_ZENY){ //Zeny Bug Fixed by Darkchild
+ clif_tradecancelled(sd);
+ clif_tradecancelled(vsd);
+ return;
+ }
+ pc_payzeny(sd,z);
+ pc_getzeny(vsd,z);
+ for(i=0;8+4*i<len;i++){
+ amount=*(short*)(p+4*i);
+ index=*(short*)(p+2+4*i)-2;
+ if(amount < 0) break; //add
+ pc_additem(sd,&vsd->status.cart[index],amount);
+
+ #ifndef TXT_ONLY
+ if(log_config.vend > 0)
+ log_vend(vsd,sd,index,amount,z);
+ #endif
+
+ vsd->vending[vend_list[i]].amount-=amount;
+ pc_cart_delitem(vsd,index,amount,0);
+ clif_vendingreport(vsd,index,amount);
+ }
+}
+
+/*==========================================
+ * 露店開設
+ *------------------------------------------
+ */
+void vending_openvending(struct map_session_data *sd,int len,char *message,int flag,unsigned char *p)
+{
+ int i;
+
+ nullpo_retv(sd);
+
+ if(!pc_checkskill(sd,MC_VENDING) || !pc_iscarton(sd)) { // cart skill and cart check [Valaris]
+ clif_skill_fail(sd,MC_VENDING,0,0);
+ return;
+ }
+
+ if(flag){
+ for(i=0;85+8*i<len;i++){
+ sd->vending[i].index=*(short*)(p+8*i)-2;
+ sd->vending[i].amount=*(short*)(p+2+8*i);
+ sd->vending[i].value=*(int*)(p+4+8*i);
+ if(sd->vending[i].value>battle_config.vending_max_value)sd->vending[i].value=battle_config.vending_max_value;
+ // カート内のアイテム数と販売するアイテム数に相違があったら中止
+ if(pc_cartitem_amount(sd,sd->vending[i].index,sd->vending[i].amount)<0 || sd->vending[i].value < 0) { // fixes by Valaris and fritz
+ clif_skill_fail(sd,MC_VENDING,0,0);
+ return;
+ }
+ }
+ sd->vender_id=sd->bl.id;
+ sd->vend_num=i;
+ strcpy(sd->message,message);
+ if(clif_openvending(sd,sd->vender_id,sd->vending) > 0)
+ clif_showvendingboard(&sd->bl,message,0);
+ else
+ sd->vender_id=0;
+ }
+}
+
diff --git a/src/map/vending.h b/src/map/vending.h
new file mode 100644
index 000000000..e5b958386
--- /dev/null
+++ b/src/map/vending.h
@@ -0,0 +1,12 @@
+// $Id: vending.h,v 1.2 2004/09/25 05:32:19 MouseJstr Exp $
+#ifndef _VENDING_H_
+#define _VENDING_H_
+
+#include "map.h"
+
+void vending_closevending(struct map_session_data *sd);
+void vending_openvending(struct map_session_data *sd,int len,char *message,int flag,unsigned char *p);
+void vending_vendinglistreq(struct map_session_data *sd,int id);
+void vending_purchasereq(struct map_session_data *sd,int len,int id,unsigned char *p);
+
+#endif // _VENDING_H_