diff options
author | amber <amber@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2004-11-14 16:18:26 +0000 |
---|---|---|
committer | amber <amber@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2004-11-14 16:18:26 +0000 |
commit | 581475bc6416790765c498aa3d611f6868ffb64a (patch) | |
tree | 347ebf88eaa76e50488f23989d67cad834f3c9b1 /src/map | |
parent | 600362764ce348c5c9de96eababff2e08bb90d4a (diff) | |
download | hercules-581475bc6416790765c498aa3d611f6868ffb64a.tar.gz hercules-581475bc6416790765c498aa3d611f6868ffb64a.tar.bz2 hercules-581475bc6416790765c498aa3d611f6868ffb64a.tar.xz hercules-581475bc6416790765c498aa3d611f6868ffb64a.zip |
Fixed some file types
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/athena@172 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src/map')
45 files changed, 70403 insertions, 70403 deletions
diff --git a/src/map/Makefile b/src/map/Makefile index cc5abc73c..3f1bab6c1 100644 --- a/src/map/Makefile +++ b/src/map/Makefile @@ -1,73 +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
+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 index df6782c84..8614d8df0 100644 --- a/src/map/Makefile.win32 +++ b/src/map/Makefile.win32 @@ -1,93 +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
+# 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 index 1e43407c8..ecdec12d9 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -1,7703 +1,7703 @@ -// $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
-ATCOMMAND_FUNC(changesex); // 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
- { AtCommand_ChangeSex, "@changesex", 1, atcommand_changesex }, // 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", ¶m1, ¶m2, ¶m3) < 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);
- if (battle_config.pc_invincible_time > 0)
- pc_setinvincibletimer(sd, battle_config.pc_invincible_time);
- 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;
-}
-
-/*==========================================
- * @changesex <sex>
- * => Changes one's sex. Argument sex can be
- * 0 or 1, m or f, male or female.
- *------------------------------------------
- */
-int
-atcommand_changesex(
- const int fd, struct map_session_data* sd,
- const char* command, const char* message)
-{
-
-// char sex[200], output[200];
-// int isex = (sd->status.sex+1)%2;
-/*
- if (!message || !*message)
- return -1;
- memset(sex, '\0', sizeof(sex));
- if(sscanf(message, "%99[^\n]", sex) < 1)
- return -1;
- str_lower(sex);
- if (strcmp(sex,"0") == 0 || strcmp(sex,"f") == 0 || strcmp(sex,"female") == 0) {
- isex = 0;
- } else if (strcmp(sex,"1") == 0 || strcmp(sex,"m") == 0 || strcmp(sex,"male") == 0) {
- isex = 1;
- } else {
- clif_displaymessage(fd,msg_table[456]);
- return 0;
- }
-*/
-// if (isex != sd->sex) {
- chrif_changesex(sd->status.account_id, ((sd->status.sex+1)%2));
-// } else {
-// sprintf(output,msg_table[460],(isex == 0)?"female":"male");
-// 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 */
+// $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 +ATCOMMAND_FUNC(changesex); // 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 + { AtCommand_ChangeSex, "@changesex", 1, atcommand_changesex }, // 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", ¶m1, ¶m2, ¶m3) < 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); + if (battle_config.pc_invincible_time > 0) + pc_setinvincibletimer(sd, battle_config.pc_invincible_time); + 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; +} + +/*========================================== + * @changesex <sex> + * => Changes one's sex. Argument sex can be + * 0 or 1, m or f, male or female. + *------------------------------------------ + */ +int +atcommand_changesex( + const int fd, struct map_session_data* sd, + const char* command, const char* message) +{ + +// char sex[200], output[200]; +// int isex = (sd->status.sex+1)%2; +/* + if (!message || !*message) + return -1; + memset(sex, '\0', sizeof(sex)); + if(sscanf(message, "%99[^\n]", sex) < 1) + return -1; + str_lower(sex); + if (strcmp(sex,"0") == 0 || strcmp(sex,"f") == 0 || strcmp(sex,"female") == 0) { + isex = 0; + } else if (strcmp(sex,"1") == 0 || strcmp(sex,"m") == 0 || strcmp(sex,"male") == 0) { + isex = 1; + } else { + clif_displaymessage(fd,msg_table[456]); + return 0; + } +*/ +// if (isex != sd->sex) { + chrif_changesex(sd->status.account_id, ((sd->status.sex+1)%2)); +// } else { +// sprintf(output,msg_table[460],(isex == 0)?"female":"male"); +// 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 index c5ba3df58..6f199cf2b 100644 --- a/src/map/atcommand.h +++ b/src/map/atcommand.h @@ -1,244 +1,244 @@ -// $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,
- AtCommand_ChangeSex,
- // 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
-
+// $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, + AtCommand_ChangeSex, + // 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 index 1561b054d..812372c31 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -1,5462 +1,5462 @@ -// $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;
- int agib = agi*(sc_data[SC_QUAGMIRE].val1*10)/100;
- agi -= agib > 50 ? 50 : agib;
- }
- 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;
- int dexb = dex*(sc_data[SC_QUAGMIRE].val1*10)/100;
- dex -= dexb > 50 ? 50 : dexb;
- }
- 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(sc_data[SC_EDP].timer != -1) // [Celest]
- batk += batk*(50+50*sc_data[SC_EDP].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 < (15*sc_data[SC_REJECTSWORD].val1)){ //反射確率は15*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(sc_data[SC_SPIDERWEB].timer!=-1 && damage > 0) // [Celest]
- if ((flag&BF_SKILL && skill_get_pl(skill_num)==3) ||
- (!flag&BF_SKILL && battle_get_attack_element(src)==3)) {
- damage<<=1;
- skill_status_change_end(bl, SC_SPIDERWEB, -1);
- }
-
- if(sc_data[SC_FOGWALL].timer != -1 && flag&BF_MAGIC)
- if(rand()%100 < sc_data[SC_FOGWALL].val2)
- damage = 0;
- }
-
- 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*(int)(3+(sd->status.base_level+1)*0.05)); // submitted by orn
- //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_GRIMTOOTH:
- damage = damage*(100+ 20*skill_lv)/100;
- 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+ 60*skill_lv)/100;
- break;
- case CH_CHAINCRUSH: // 連柱崩撃
- damage = damage*(100+ 60*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+ 40*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*(200+100*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 && t_sc_data ) { // 必中攻撃
- if(t_sc_data[SC_FOGWALL].timer != -1 && flag&BF_LONG)
- hitrate -= 50;
- if (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(hitrate < 1000000)
- hitrate = ( (hitrate>95)?95: ((hitrate<5)?5:hitrate) );
- 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(t_sc_data[SC_FOGWALL].timer != -1 && flag&BF_LONG)
- cardfix=cardfix*(100-t_sc_data[SC_FOGWALL].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 = 500+300*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;
- } else if(skill_num != CR_GRANDCROSS && t_sc_data && t_sc_data[SC_POISONREACT].timer != -1) { // poison react [Celest]
- //memset(&wd,0,sizeof(wd));
- t_sc_data[SC_POISONREACT].val3 = 0;
- t_sc_data[SC_POISONREACT].val4 = 1;
- t_sc_data[SC_POISONREACT].val3 = src->id;
- return wd;
- }
- }
- 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_GRIMTOOTH:
- damage = damage*(100+ 20*skill_lv)/100;
- 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+ 60*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+ 40*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*(200+100*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* (int) (3 + (tsd->status.base_level+1)*0.04); // submitted by orn
- //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 && t_sc_data ) { // 必中攻撃
- if(t_sc_data[SC_FOGWALL].timer != -1 && flag&BF_LONG)
- hitrate -= 50;
- if (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(hitrate < 1000000)
- hitrate = ( (hitrate>95)?95: ((hitrate<5)?5:hitrate) );
- 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(t_sc_data[SC_FOGWALL].timer != -1 && flag&BF_LONG)
- cardfix=cardfix*(100-t_sc_data[SC_FOGWALL].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 = 500+300*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;
- } else if(skill_num != CR_GRANDCROSS && t_sc_data && t_sc_data[SC_POISONREACT].timer != -1) { // poison react [Celest]
- //memset(&wd,0,sizeof(wd));
- t_sc_data[SC_POISONREACT].val3 = 0;
- t_sc_data[SC_POISONREACT].val4 = 1;
- t_sc_data[SC_POISONREACT].val3 = src->id;
- return wd;
- }
- }
-//オートカウンター処理ここまで
-
- 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)
- cri += 200;
- }
-
- 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_GRIMTOOTH:
- damage = damage*(100+ 20*skill_lv)/100;
- damage2 = damage2*(100+ 20*skill_lv)/100;
- 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+ 60*skill_lv)/100;
- damage2 = damage2*(100+ 60*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+ 40*skill_lv)/100;
- damage2 = damage2*(100+ 40*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*(200+100*skill_lv)/100;
- damage2 = damage2*(200+100*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*9/100;
- damage = damage*damage3*(90+10*skill_lv)/10000;
- damage2 = damage2*damage3*(90+10*skill_lv)/10000;
- }
- 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;
- }
-
- // 回避修正
- if( hitrate < 1000000 && t_sc_data ) { // 必中攻撃
- if(t_sc_data[SC_FOGWALL].timer != -1 && flag&BF_LONG)
- hitrate -= 50;
- if (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;
- }
- hitrate = (hitrate<5)?5:hitrate;
- 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(t_sc_data[SC_FOGWALL].timer != -1 && flag&BF_LONG)
- cardfix=cardfix*(100-t_sc_data[SC_FOGWALL].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 = 500+300*skill_lv;
- damage2 = 500+300*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_STEELCROW); // Celest
- damage=((150+50*skill_lv)*(dex/10+int_/2+skill*3+40)*2)/100;
- 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_POISONREACT].timer != -1 && t_sc_data[SC_POISONREACT].val4 > 0) { // poison react [Celest]
- if(t_sc_data[SC_POISONREACT].val3 == src->id) {
- struct map_session_data *tsd = (struct map_session_data *)target;
- if ((src->type == BL_MOB && battle_get_elem_type(src)==5) || (src->type == BL_PC && battle_get_attack_element(src)==5)) {
- t_sc_data[SC_POISONREACT].val2 = 0;
- battle_weapon_attack(target,src,tick,flag|t_sc_data[SC_POISONREACT].val1);
- } else {
- skill_use_id(tsd,src->id,TF_POISON,5);
- --t_sc_data[SC_POISONREACT].val2;
- }
- if (t_sc_data[SC_POISONREACT].val2<=0)
- skill_status_change_end(target,SC_POISONREACT,-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;
-}
+// $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; + int agib = agi*(sc_data[SC_QUAGMIRE].val1*10)/100; + agi -= agib > 50 ? 50 : agib; + } + 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; + int dexb = dex*(sc_data[SC_QUAGMIRE].val1*10)/100; + dex -= dexb > 50 ? 50 : dexb; + } + 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(sc_data[SC_EDP].timer != -1) // [Celest] + batk += batk*(50+50*sc_data[SC_EDP].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 < (15*sc_data[SC_REJECTSWORD].val1)){ //反射確率は15*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(sc_data[SC_SPIDERWEB].timer!=-1 && damage > 0) // [Celest] + if ((flag&BF_SKILL && skill_get_pl(skill_num)==3) || + (!flag&BF_SKILL && battle_get_attack_element(src)==3)) { + damage<<=1; + skill_status_change_end(bl, SC_SPIDERWEB, -1); + } + + if(sc_data[SC_FOGWALL].timer != -1 && flag&BF_MAGIC) + if(rand()%100 < sc_data[SC_FOGWALL].val2) + damage = 0; + } + + 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*(int)(3+(sd->status.base_level+1)*0.05)); // submitted by orn + //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_GRIMTOOTH: + damage = damage*(100+ 20*skill_lv)/100; + 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+ 60*skill_lv)/100; + break; + case CH_CHAINCRUSH: // 連柱崩撃 + damage = damage*(100+ 60*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+ 40*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*(200+100*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 && t_sc_data ) { // 必中攻撃 + if(t_sc_data[SC_FOGWALL].timer != -1 && flag&BF_LONG) + hitrate -= 50; + if (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(hitrate < 1000000) + hitrate = ( (hitrate>95)?95: ((hitrate<5)?5:hitrate) ); + 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(t_sc_data[SC_FOGWALL].timer != -1 && flag&BF_LONG) + cardfix=cardfix*(100-t_sc_data[SC_FOGWALL].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 = 500+300*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; + } else if(skill_num != CR_GRANDCROSS && t_sc_data && t_sc_data[SC_POISONREACT].timer != -1) { // poison react [Celest] + //memset(&wd,0,sizeof(wd)); + t_sc_data[SC_POISONREACT].val3 = 0; + t_sc_data[SC_POISONREACT].val4 = 1; + t_sc_data[SC_POISONREACT].val3 = src->id; + return wd; + } + } + 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_GRIMTOOTH: + damage = damage*(100+ 20*skill_lv)/100; + 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+ 60*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+ 40*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*(200+100*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* (int) (3 + (tsd->status.base_level+1)*0.04); // submitted by orn + //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 && t_sc_data ) { // 必中攻撃 + if(t_sc_data[SC_FOGWALL].timer != -1 && flag&BF_LONG) + hitrate -= 50; + if (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(hitrate < 1000000) + hitrate = ( (hitrate>95)?95: ((hitrate<5)?5:hitrate) ); + 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(t_sc_data[SC_FOGWALL].timer != -1 && flag&BF_LONG) + cardfix=cardfix*(100-t_sc_data[SC_FOGWALL].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 = 500+300*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; + } else if(skill_num != CR_GRANDCROSS && t_sc_data && t_sc_data[SC_POISONREACT].timer != -1) { // poison react [Celest] + //memset(&wd,0,sizeof(wd)); + t_sc_data[SC_POISONREACT].val3 = 0; + t_sc_data[SC_POISONREACT].val4 = 1; + t_sc_data[SC_POISONREACT].val3 = src->id; + return wd; + } + } +//オートカウンター処理ここまで + + 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) + cri += 200; + } + + 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_GRIMTOOTH: + damage = damage*(100+ 20*skill_lv)/100; + damage2 = damage2*(100+ 20*skill_lv)/100; + 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+ 60*skill_lv)/100; + damage2 = damage2*(100+ 60*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+ 40*skill_lv)/100; + damage2 = damage2*(100+ 40*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*(200+100*skill_lv)/100; + damage2 = damage2*(200+100*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*9/100; + damage = damage*damage3*(90+10*skill_lv)/10000; + damage2 = damage2*damage3*(90+10*skill_lv)/10000; + } + 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; + } + + // 回避修正 + if( hitrate < 1000000 && t_sc_data ) { // 必中攻撃 + if(t_sc_data[SC_FOGWALL].timer != -1 && flag&BF_LONG) + hitrate -= 50; + if (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; + } + hitrate = (hitrate<5)?5:hitrate; + 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(t_sc_data[SC_FOGWALL].timer != -1 && flag&BF_LONG) + cardfix=cardfix*(100-t_sc_data[SC_FOGWALL].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 = 500+300*skill_lv; + damage2 = 500+300*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_STEELCROW); // Celest + damage=((150+50*skill_lv)*(dex/10+int_/2+skill*3+40)*2)/100; + 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_POISONREACT].timer != -1 && t_sc_data[SC_POISONREACT].val4 > 0) { // poison react [Celest] + if(t_sc_data[SC_POISONREACT].val3 == src->id) { + struct map_session_data *tsd = (struct map_session_data *)target; + if ((src->type == BL_MOB && battle_get_elem_type(src)==5) || (src->type == BL_PC && battle_get_attack_element(src)==5)) { + t_sc_data[SC_POISONREACT].val2 = 0; + battle_weapon_attack(target,src,tick,flag|t_sc_data[SC_POISONREACT].val1); + } else { + skill_use_id(tsd,src->id,TF_POISON,5); + --t_sc_data[SC_POISONREACT].val2; + } + if (t_sc_data[SC_POISONREACT].val2<=0) + skill_status_change_end(target,SC_POISONREACT,-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 index d4f680509..1ff90bdd7 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -1,345 +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
+// $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 index 051d9609a..75788f03b 100644 --- a/src/map/chat.c +++ b/src/map/chat.c @@ -1,378 +1,378 @@ -// $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;
- }
- if(chatid == sd->chatID) //Double Chat fix by Alex14, thx CHaNGeTe
- {
- 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;
-}
+// $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; + } + if(chatid == sd->chatID) //Double Chat fix by Alex14, thx CHaNGeTe + { + 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 index 15559f188..276160251 100644 --- a/src/map/chat.h +++ b/src/map/chat.h @@ -1,22 +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
+// $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 index 876c71758..6e53bd6d2 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -1,1050 +1,1050 @@ -// $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;
-}
-
-/*==========================================
- * 性別変化要求
- *------------------------------------------
- */
-int chrif_changesex(int id, int sex) {
- WFIFOW(char_fd,0) = 0x3000;
- WFIFOW(char_fd,2) = 9;
- WFIFOL(char_fd,4) = id;
- WFIFOB(char_fd,8) = sex;
- printf("chrif : sent 0x3000(changesex)\n");
- WFIFOSET(char_fd,9);
- 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(×tamp));
- 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;
-}
-
-/*==========================================
- * キャラクター切断通知
- *------------------------------------------
- */
-int chrif_chardisconnect(struct map_session_data *sd)
-{
- nullpo_retr(-1, sd);
-
- if(char_fd<=0)
- return -1;
-
- WFIFOW(char_fd,0)=0x2b18;
- WFIFOL(char_fd,2)=sd->status.account_id;
- WFIFOL(char_fd,6)=sd->status.char_id;
- WFIFOSET(char_fd,10);
- //printf("chrif: char disconnect: %d %s\n",sd->bl.id,sd->status.name);
- 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;
-}
+// $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; +} + +/*========================================== + * 性別変化要求 + *------------------------------------------ + */ +int chrif_changesex(int id, int sex) { + WFIFOW(char_fd,0) = 0x3000; + WFIFOW(char_fd,2) = 9; + WFIFOL(char_fd,4) = id; + WFIFOB(char_fd,8) = sex; + printf("chrif : sent 0x3000(changesex)\n"); + WFIFOSET(char_fd,9); + 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(×tamp)); + 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; +} + +/*========================================== + * キャラクター切断通知 + *------------------------------------------ + */ +int chrif_chardisconnect(struct map_session_data *sd) +{ + nullpo_retr(-1, sd); + + if(char_fd<=0) + return -1; + + WFIFOW(char_fd,0)=0x2b18; + WFIFOL(char_fd,2)=sd->status.account_id; + WFIFOL(char_fd,6)=sd->status.char_id; + WFIFOSET(char_fd,10); + //printf("chrif: char disconnect: %d %s\n",sd->bl.id,sd->status.name); + 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 index 858fdeaa7..de20c3086 100644 --- a/src/map/chrif.h +++ b/src/map/chrif.h @@ -1,31 +1,31 @@ -// $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 chrif_changesex(int id, int sex);
-int chrif_chardisconnect(struct map_session_data *sd);
-
-int do_init_chrif(void);
-
-#endif
+// $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 chrif_changesex(int id, int sex); +int chrif_chardisconnect(struct map_session_data *sd); + +int do_init_chrif(void); + +#endif diff --git a/src/map/clif.c b/src/map/clif.c index 6a4094286..544a8fdfc 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -1,10377 +1,10377 @@ -// $Id: clif.c 2200 2004-11-07 11:49:58Z Yor $
-
-#define DUMP_UNKNOWN_PACKET 1
-
-#include <stdio.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdarg.h>
-#ifdef __WIN32
-#define __USE_W32_SOCKETS
-#include <windows.h>
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#endif
-#include <time.h>
-
-#include "../common/socket.h"
-#include "../common/timer.h"
-#include "../common/malloc.h"
-#include "../common/version.h"
-#include "../common/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"
-
-#ifdef MEMWATCH
-#include "memwatch.h"
-#endif
-
-#define STATE_BLIND 0x10
-
-static const int packet_len_table[0x220] = {
- 10, 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, 0, 0,
-//#0x0040
- 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, 55, 17, 3, 37, 46, -1, 23, -1, 3,108, 3, 2,
-#if PACKETVER < 2
- 3, 28, 19, 11, 3, -1, 9, 5, 52, 51, 56, 58, 41, 2, 6, 6,
-#else // 78-7b 亀島以降 lv99エフェクト用
- 3, 28, 19, 11, 3, -1, 9, 5, 54, 53, 58, 60, 41, 2, 6, 6,
-#endif
-//#0x0080
- 7, 3, 2, 2, 2, 5, 16, 12, 10, 7, 29, 23, -1, -1, -1, 0, // 0x8b unknown... size 2 or 23?
- 7, 22, 28, 2, 6, 30, -1, -1, 3, -1, -1, 5, 9, 17, 17, 6,
- 23, 6, 6, -1, -1, -1, -1, 8, 7, 6, 7, 4, 7, 0, -1, 6,
- 8, 8, 3, 3, -1, 6, 6, -1, 7, 6, 2, 5, 6, 44, 5, 3,
-//#0x00C0
- 7, 2, 6, 8, 6, 7, -1, -1, -1, -1, 3, 3, 6, 6, 2, 27,
- 3, 4, 4, 2, -1, -1, 3, -1, 6, 14, 3, -1, 28, 29, -1, -1,
- 30, 30, 26, 2, 6, 26, 3, 3, 8, 19, 5, 2, 3, 2, 2, 2,
- 3, 2, 6, 8, 21, 8, 8, 2, 2, 26, 3, -1, 6, 27, 30, 10,
-
-//#0x0100
- 2, 6, 6, 30, 79, 31, 10, 10, -1, -1, 4, 6, 6, 2, 11, -1,
- 10, 39, 4, 10, 31, 35, 10, 18, 2, 13, 15, 20, 68, 2, 3, 16,
- 6, 14, -1, -1, 21, 8, 8, 8, 8, 8, 2, 2, 3, 4, 2, -1,
- 6, 86, 6, -1, -1, 7, -1, 6, 3, 16, 4, 4, 4, 6, 24, 26,
-//#0x0140
- 22, 14, 6, 10, 23, 19, 6, 39, 8, 9, 6, 27, -1, 2, 6, 6,
- 110, 6, -1, -1, -1, -1, -1, 6, -1, 54, 66, 54, 90, 42, 6, 42,
- -1, -1, -1, -1, -1, 30, -1, 3, 14, 3, 30, 10, 43, 14,186,182,
- 14, 30, 10, 3, -1, 6,106, -1, 4, 5, 4, -1, 6, 7, -1, -1,
-//#0x0180
- 6, 3,106, 10, 10, 34, 0, 6, 8, 4, 4, 4, 29, -1, 10, 6,
-#if PACKETVER < 1
- 90, 86, 24, 6, 30,102, 8, 4, 8, 4, 14, 10, -1, 6, 2, 6,
-#else // 196 comodo以降 状態表示アイコン用
- 90, 86, 24, 6, 30,102, 9, 4, 8, 4, 14, 10, -1, 6, 2, 6,
-#endif
- 3, 3, 35, 5, 11, 26, -1, 4, 4, 6, 10, 12, 6, -1, 4, 4,
- 11, 7, -1, 67, 12, 18,114, 6, 3, 6, 26, 26, 26, 26, 2, 3,
-//#0x01C0, Set 0x1d5=-1
- 2, 14, 10, -1, 22, 22, 4, 2, 13, 97, 0, 9, 9, 30, 6, 28,
- 8, 14, 10, 35, 6, -1, 4, 11, 54, 53, 60, 2, -1, 47, 33, 6,
- 30, 8, 34, 14, 2, 6, 26, 2, 28, 81, 6, 10, 26, 2, -1, -1,
- -1, -1, 20, 10, 32, 9, 34, 14, 2, 6, 48, 56, -1, 4, 5, 10,
-//#0x200
- 26, -1, 26, 10, 18, 26, 11, 34, 14, 36, 10, 19, 0, -1, 24, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-// size list for each packet version after packet version 4.
-static int packet_size_table[9][0x220];
-
-// 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];
-
-/*==========================================
- * 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 {
- if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version
- 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) {
- if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version
- 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) {
- if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version
- 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;
- if (packet_size_table[cd->usersd[i]->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version
- if (cd->usersd[i]->fd >=0 && session[cd->usersd[i]->fd]) // Added check to see if session exists [PoW]
- 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;
- if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version
- 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) {
- if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version
- memcpy(WFIFOP(sd->fd,0), buf, len);
- WFIFOSET(sd->fd,len);
- }
- }
- }
- }
- }
- break;
- case SELF:
- sd = (struct map_session_data *)bl;
- if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version
- 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;
- if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version
- 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) {
- if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version
- 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;
- if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version
- 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_len_table[0x73]);
-
- 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_len_table[0x81]);
-
- 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_len_table[0xb3]);
-
- 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_len_table[0x9e];
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-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_len_table[0x9e], &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_len_table[0xa1], &fitem->bl, AREA);
- } else {
- memcpy(WFIFOP(fd,0), buf, 6);
- WFIFOSET(fd,packet_len_table[0xa1]);
- }
-
- 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_len_table[0x80], bl, AREA);
- } else {
- WBUFB(buf,6) = type;
- clif_send(buf, packet_len_table[0x80], 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;
-
- tmpbl = (struct block_list*)aCalloc(1, sizeof(struct block_list));
-
- 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_len_table[0x80]);
-
- return 0;
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static int clif_set0078(struct map_session_data *sd, unsigned char *buf) {
- int level;
-
- 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_len_table[0x78];
- }
-
-#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_len_table[0x78];
-#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_len_table[0x1d8];
-#endif
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static int clif_set007b(struct map_session_data *sd,unsigned char *buf) {
- int level;
-
- 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_len_table[0x7b];
- }
-
-#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_len_table[0x7b];
-#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_len_table[0x1da];
-#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_len_table[0x1b0],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_len_table[0x1b0],&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_len_table[0x1a4]);
-
- WBUFW(buf,0)=0x1a4;
- WBUFB(buf,2)=3;
- WBUFL(buf,3)=md->bl.id;
- WBUFL(buf,7)=nameid;
-
- clif_send(buf,packet_len_table[0x1a4],&md->bl,AREA);
-
- return 0;
-}
-
-/*==========================================
- * MOB表示1
- *------------------------------------------
- */
-static int clif_mob0078(struct mob_data *md, unsigned char *buf)
-{
- int level;
-
- memset(buf,0,packet_len_table[0x78]);
-
- 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 && md->guild_id) { // 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,22)=g->emblem_id;
- WBUFL(buf,26)=gc->guild_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_len_table[0x78];
-}
-
-/*==========================================
- * MOB表示2
- *------------------------------------------
- */
-static int clif_mob007b(struct mob_data *md, unsigned char *buf) {
- int level;
-
- memset(buf,0,packet_len_table[0x7b]);
-
- 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 && md->guild_id) { // 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_len_table[0x7b];
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static int clif_npc0078(struct npc_data *nd, unsigned char *buf) {
- struct guild *g;
-
- nullpo_retr(0, nd);
-
- memset(buf,0,packet_len_table[0x78]);
-
- 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_len_table[0x78];
-}
-
-// 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_len_table[0x7b]);
-
- 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_len_table[0x7b];
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static int clif_pet0078(struct pet_data *pd, unsigned char *buf) {
- int view,level;
-
- nullpo_retr(0, pd);
-
- memset(buf,0,packet_len_table[0x78]);
-
- 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_len_table[0x78];
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static int clif_pet007b(struct pet_data *pd, unsigned char *buf) {
- int view,level;
-
- nullpo_retr(0, pd);
-
- memset(buf,0,packet_len_table[0x7b]);
-
- 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_len_table[0x7b];
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-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_len_table[0x1e1];
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-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_len_table[0x192]);
-
- 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_len_table[0x119]);
-
- 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_len_table[0x119], &sd->bl, SELF);
-
- memset(buf, 0, packet_len_table[0x7c]);
-
- 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_len_table[0x7c], &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_len_table[0x79], &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_len_table[0x1d9], &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_len_table[0x7c]);
-
- 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_len_table[0x7c],&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_len_table[0x7c]);
-
- 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_len_table[0x7c],&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_len_table[0x7c]);
-
- 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_len_table[0x7c],&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_len_table[0x7f]);
-
- 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_len_table[0x87]);
-
- 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) {
- struct map_session_data *sd;
-
- // if player is not already in the game (double connection probably)
- if ((sd = session[fd]->session_data) == NULL) {
- // limited timer, just to send information.
- add_timer(gettick() + 1000, clif_waitclose, fd, 0);
- } else
- 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_len_table[0x91]);
-
- 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_len_table[0x92]);
-
- 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_len_table[0x88], 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_len_table[0xc4]);
-
- 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_len_table[0xb5]);
-
- 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_len_table[0xb6]);
-
- 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_len_table[0x142]);
-
- 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_len_table[0x1d4]);
-
- 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_len_table[0x144]);
-
- 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_len_table[0x1b3]);
-
- 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_len_table[0xa0]);
- 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_len_table[0xaf]);
-
- 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_len_table[0x1ab],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_len_table[0xc3],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_len_table[0x1d7],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_len_table[0x1d7],bl,AREA);
- } else {
- WBUFW(buf,0)=0xc3;
- WBUFL(buf,2)=bl->id;
- WBUFB(buf,6)=type;
- WBUFB(buf,7)=val;
- clif_send(buf,packet_len_table[0xc3],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_len_table[0xbd]);
-
- 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_len_table[0x013c]);
-
- 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_len_table[0x013b]);
-
- 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_len_table[0xbc]);
-
- 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_len_table[0xaa]);
-
- 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_len_table[0xac]);
-
- 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_len_table[0x19b],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_len_table[0x1f3]);
-
- WBUFW(buf,0) = 0x1f3;
- WBUFL(buf,2) = bl->id;
- WBUFL(buf,6) = type;
-
- clif_send(buf, packet_len_table[0x1f3], 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_len_table[0x119],bl,AREA_WOS);
- clif_spawnpc(sd);
- } else
- clif_send(buf,packet_len_table[0x119],bl,AREA);
- } else
- clif_send(buf,packet_len_table[0x119],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_len_table[0xa8]);
- }
- 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_len_table[0xa8]);
-#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_len_table[0x1c8],&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_len_table[0xd6]);
-
- 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_len_table[0xd8]);
- WFIFOSET(fd,packet_len_table[0xd8]);
- } else {
- clif_send(buf,packet_len_table[0xd8],*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_len_table[0xda]);
-
- 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_len_table[0xdc],&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_len_table[0xe1]*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_len_table[0xdd],&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_len_table[0xe5]);
-
- 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_len_table[0xe7]);
-
- 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_len_table[0xe9]);
-
- 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_len_table[0xea]);
-
- 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_len_table[0xec]);
-
- 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_len_table[0xee]);
-
- 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_len_table[0xf0]);
-
- 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_len_table[0xf2]);
-
- 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_len_table[0xf4]);
-
- 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_len_table[0xf2]);
-
- 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_len_table[0xf4]);
-
- 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_len_table[0xf6]);
-
- 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_len_table[0xf8]);
-
- 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_len_table[0x1e1]);
- }
- 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_len_table[0x8a],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_len_table[0x9d]);
-}
-/*==========================================
- * 場所スキルエフェクトが視界に入る
- *------------------------------------------
- */
-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_len_table[0x11f]);
- 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_len_table[0x11f]);
-#else
- memset(WFIFOP(fd,0),0,packet_len_table[0x1c9]);
- WFIFOW(fd, 0)=0x1c9;
- WFIFOL(fd, 2)=unit->bl.id;
- WFIFOL(fd, 6)=unit->group->src_id;
- WFIFOW(fd,10)=unit->bl.x;
- WFIFOW(fd,12)=unit->bl.y;
- WFIFOB(fd,14)=unit->group->unit_id;
- WFIFOB(fd,15)=1;
- 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_len_table[0x1c9]);
-#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_len_table[0x120]);
- 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_len_table[0x1ac],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_len_table[0x147]);
-
- 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_len_table[0x10e]);
-
- 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_len_table[0x13e], 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_len_table[0x1b9], 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_len_table[0x110]);
-
- 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_len_table[0x114],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_len_table[0x1de],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_len_table[0x115],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_len_table[0x11a],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_len_table[0x117],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_len_table[0x11f]);
- 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_len_table[0x11f],&unit->bl,AREA);
-#else
- memset(WBUFP(buf, 0),0,packet_len_table[0x1c9]);
- 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_len_table[0x1c9],&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_len_table[0x120],&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_len_table[0x11c]);
- 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_len_table[0x11e]);
- 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_len_table[0x189]);
- 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_len_table[0x18c],&sd->bl,PARTY_AREA);
- else{
- memcpy(WFIFOP(sd->fd,0),buf,packet_len_table[0x18c]);
- WFIFOSET(sd->fd,packet_len_table[0x18c]);
- }
- 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_len_table[0x196],bl,AREA);
- return 0;
-}
-
-/*==========================================
- * Send message (modified by [Yor])
- *------------------------------------------
- */
-int clif_displaymessage(const int fd, char* mes)
-{
- //Console [Wizputer]
- if (fd == 0)
- printf("\033[0;36mConsole: \033[0m\033[1m%s\033[0m\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 *buf;
- int lp;
-
- lp = (flag & 0x10) ? 8 : 4;
- buf = (unsigned char*)aCalloc(len + lp, sizeof(unsigned char));
-
- 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) 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_len_table[0x13d]);
-
- 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_len_table[0x148],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_len_table[0x199]);
-
- 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_len_table[0x19a]);
- } 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_len_table[0x19a],&sd->bl,AREA);
- else
- clif_send(buf,packet_len_table[0x19a],&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_len_table[0x199],&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_len_table[0x188]);
-
- 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_len_table[0x98]);
- 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_len_table[0x194]);
- }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_len_table[0x17d]);
- 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_len_table[0x179]);
- 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_len_table[0x147]);
- 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_len_table[0x124]);
- 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_len_table[0x125]);
-
- 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_len_table[0x12d]);
-
- 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_len_table[0x131]);
- WFIFOSET(fd,packet_len_table[0x131]);
- }else{
- clif_send(buf,packet_len_table[0x131],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_len_table[0x132]);
- WFIFOSET(fd,packet_len_table[0x132]);
- }else{
- clif_send(buf,packet_len_table[0x132],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_len_table[0x135]);
-
- 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_len_table[0x137]);
-
- 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_len_table[0xfa]);
- 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_len_table[0xfe]);
- 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_len_table[0xfd]);
- 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_len_table[0x101],&sd->bl,PARTY);
- else {
- memcpy(WFIFOP(sd->fd,0),buf,packet_len_table[0x101]);
- WFIFOSET(sd->fd,packet_len_table[0x101]);
- }
- 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_len_table[0x105],&sd->bl,PARTY);
- } else if (sd!=NULL) {
- memcpy(WFIFOP(sd->fd,0),buf,packet_len_table[0x105]);
- WFIFOSET(sd->fd,packet_len_table[0x105]);
- }
- 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_len_table[0x107],&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_len_table[0x106],&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_len_table[0x104],&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_len_table[0x139]);
- 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_len_table[0x18f]);
- 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_len_table[0x19e]);
-
- 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_len_table[0x1a0]);
-
- 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_len_table[0x1a4]);
-
- 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_len_table[0x1a2]);
-
- 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_len_table[0x1aa]);
-
- 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_len_table[0x1aa],&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_len_table[0x1a4]);
-
- WBUFW(buf,0)=0x1a4;
- WBUFB(buf,2)=4;
- WBUFL(buf,3)=bl->id;
- WBUFL(buf,7)=param;
-
- clif_send(buf,packet_len_table[0x1a4],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_len_table[0x1a4]);
-
- 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_len_table[0x1a4],&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_len_table[0x1a3]);
-
- 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_len_table[0x1cd]);
- 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_len_table[0x1cf],&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_len_table[0x1d0],&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_len_table[0x1d2],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_len_table[0x1d1],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_len_table[0x192],&bl,AREA);
- else
- clif_send(buf,packet_len_table[0x192],&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_len_table[0x10c],&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_len_table[0x10a]);
- 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_len_table[0x10b]);
- 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_len_table[0x167]);
- 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_len_table[0x16c]);
- 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_len_table[0x16c]);
- 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_len_table[0x16d],&sd->bl,GUILD);
- }else
- clif_send(buf,packet_len_table[0x16d],&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_len_table[0x14e]);
- 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_len_table[WFIFOW(fd,0)]);
- 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_len_table[0x16f]);
- 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_len_table[0x16a]);
- 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_len_table[0x169]);
- 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_len_table[0x15a],&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_len_table[0x15c],&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 *buf;
-
- buf = (unsigned char*)aCalloc(len + 4, sizeof(unsigned char));
-
- 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) 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_len_table[0x171]);
- 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_len_table[0x173]);
- 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_len_table[0x184]);
- 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_len_table[0x181]);
- 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_len_table[0x185],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_len_table[0x15e]);
- 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_len_table[0xc0],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_len_table[0x191],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_len_table[0x1ea], 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_len_table[0x1e6]&sd->bl,AREA);
- }
- return;
-}
-*/
-/*==========================================
- * 座る
- *------------------------------------------
- */
-void clif_sitting(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_len_table[0x8a], &sd->bl, AREA);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-int clif_disp_onlyself(struct map_session_data *sd, char *mes, int len)
-{
- unsigned char *buf;
-
- nullpo_retr(0, sd);
-
- buf = (unsigned char*)aCalloc(len + 8, sizeof(unsigned char));
-
- 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) 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_len_table[0xcd]);
- return 0;
-}
-
-void clif_parse_QuitGame(int fd,struct map_session_data *sd);
-
-int clif_GM_kick(struct map_session_data *sd,struct map_session_data *tsd,int type)
-{
- nullpo_retr(0, tsd);
-
- if(type)
- clif_GM_kickack(sd,tsd->status.account_id);
- tsd->opt1 = tsd->opt2 = 0;
- WFIFOW(tsd->fd,0) = 0x18b;
- WFIFOW(tsd->fd,2) = 0;
- WFIFOSET(tsd->fd,packet_len_table[0x18b]);
- clif_setwaitclose(tsd->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_len_table[0xd1]);
-
- 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_len_table[0xd2]);
-
- 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_len_table[0x1d3]);
-
- 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_len_table[0x1f3]);
-
- WBUFW(buf,0) = 0x1f3;
- WBUFL(buf,2) = bl->id;
- WBUFL(buf,6) = type;
-
- if (flag == 2) {
- struct map_session_data *sd;
- 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_len_table[0x1f3], bl, SELF);
- else if (!flag)
- clif_send(buf, packet_len_table[0x1f3], bl, AREA);
-
- return 0;
-
-}
-// ------------
-// clif_parse_*
-// ------------
-// パケット読み取って色々操作
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_WantToConnection(int fd, struct map_session_data *sd)
-{
- struct map_session_data *old_sd;
- int account_id; // account_id in the packet 0x72 or 0x7E
-
- if (sd) {
- if (battle_config.error_log)
- printf("clif_parse_WantToConnection : invalid request?\n");
- return;
- }
-
- // 0x72
- if (RFIFOW(fd,0) == 0x72) {
- //printf("Received bytes %d with packet 0x72.\n", RFIFOREST(fd));
- if (RFIFOREST(fd) >= 39 && (RFIFOB(fd,38) == 0 || RFIFOB(fd,38) == 1)) // 00 = Female, 01 = Male
- account_id = RFIFOL(fd,12);
- else if (RFIFOREST(fd) >= 22 && (RFIFOB(fd,21) == 0 || RFIFOB(fd,21) == 1)) // 00 = Female, 01 = Male
- account_id = RFIFOL(fd,5);
- else // old packet version
- account_id = RFIFOL(fd,2);
- // 0x7E
- } else if (RFIFOW(fd,0) == 0x7E) {
- //printf("Received bytes %d with packet 0x7E.\n", RFIFOREST(fd));
- if (RFIFOREST(fd) >= 37 && (RFIFOB(fd,36) == 0 || RFIFOB(fd,36) == 1)) // 00 = Female, 01 = Male
- account_id = RFIFOL(fd,9);
- else
- account_id = RFIFOL(fd,12);
- // 0xF5
- } else {
- //printf("Received bytes %d with packet 0xF5.\n", RFIFOREST(fd));
- if (RFIFOREST(fd) >= 34 && (RFIFOB(fd,33) == 0 || RFIFOB(fd,33) == 1)) // 00 = Female, 01 = Male
- account_id = RFIFOL(fd,7);
- else if (RFIFOREST(fd) >= 33 && (RFIFOB(fd,32) == 0 || RFIFOB(fd,32) == 1)) // 00 = Female, 01 = Male
- account_id = RFIFOL(fd,12);
- else if (RFIFOREST(fd) >= 32 && (RFIFOB(fd,31) == 0 || RFIFOB(fd,31) == 1)) // 00 = Female, 01 = Male
- account_id = RFIFOL(fd,10);
- else // 29 28 28
- account_id = RFIFOL(fd,5);
- }
-
- // if same account already connected, we disconnect the 2 sessions
- if ((old_sd = map_id2sd(account_id)) != NULL) {
- clif_authfail_fd(fd, 2); // same id
- clif_authfail_fd(old_sd->fd, 2); // same id
- } else {
- sd = session[fd]->session_data = (struct map_session_data*)aCalloc(1, sizeof(struct map_session_data));
- sd->fd = fd;
-
- // 0x72
- if (RFIFOW(fd,0) == 0x72) {
- if (RFIFOREST(fd) >= 39 && (RFIFOB(fd,38) == 0 || RFIFOB(fd,38) == 1)) { // 00 = Female, 01 = Male
- sd->packet_ver = 7; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- pc_setnewpc(sd, account_id, RFIFOL(fd,22), RFIFOL(fd,30), RFIFOL(fd,34), RFIFOB(fd,38), fd);
- } else if (RFIFOREST(fd) >= 22 && (RFIFOB(fd,21) == 0 || RFIFOB(fd,21) == 1)) { // 00 = Female, 01 = Male
- sd->packet_ver = 6; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- pc_setnewpc(sd, account_id, RFIFOL(fd,9), RFIFOL(fd,13), RFIFOL(fd,17), RFIFOB(fd,21), fd);
- } else { // old packet version
- sd->packet_ver = 5; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- pc_setnewpc(sd, account_id, RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOB(fd,18), fd);
- }
- // 0x7E
- } else if (RFIFOW(fd,0) == 0x7E) {
- if (RFIFOREST(fd) >= 37 && (RFIFOB(fd,36) == 0 || RFIFOB(fd,36) == 1)) { // 00 = Female, 01 = Male
- sd->packet_ver = 9; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- pc_setnewpc(sd, account_id, RFIFOL(fd,21), RFIFOL(fd,28), RFIFOL(fd,32), RFIFOB(fd,36), fd);
- } else {
- sd->packet_ver = 8; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- pc_setnewpc(sd, account_id, RFIFOL(fd,18), RFIFOL(fd,24), RFIFOL(fd,28), RFIFOB(fd,32), fd);
- }
- // 0xF5
- } else {
- if (RFIFOREST(fd) >= 34 && (RFIFOB(fd,33) == 0 || RFIFOB(fd,33) == 1)) { // 00 = Female, 01 = Male
- sd->packet_ver = 10; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- pc_setnewpc(sd, account_id, RFIFOL(fd,15), RFIFOL(fd,25), RFIFOL(fd,29), RFIFOB(fd,33), fd);
- } else if (RFIFOREST(fd) >= 33 && (RFIFOB(fd,32) == 0 || RFIFOB(fd,32) == 1)) { // 00 = Female, 01 = Male
- sd->packet_ver = 12; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- pc_setnewpc(sd, account_id, RFIFOL(fd,18), RFIFOL(fd,24), RFIFOL(fd,28), RFIFOB(fd,32), fd);
- } else if (RFIFOREST(fd) >= 32 && (RFIFOB(fd,31) == 0 || RFIFOB(fd,31) == 1)) { // 00 = Female, 01 = Male
- sd->packet_ver = 11; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- pc_setnewpc(sd, account_id, RFIFOL(fd,17), RFIFOL(fd,23), RFIFOL(fd,27), RFIFOB(fd,31), fd);
- } else { // 29
- sd->packet_ver = 13; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- pc_setnewpc(sd, account_id, RFIFOL(fd,14), RFIFOL(fd,20), RFIFOL(fd,24), RFIFOB(fd,28), fd);
- }
- }
-
- WFIFOL(fd,0) = sd->bl.id;
- WFIFOSET(fd,4);
-
- map_addiddb(&sd->bl);
-
- chrif_authreq(sd);
- }
-
- return;
-}
-
-/*==========================================
- * 007d クライアント側マップ読み込み完了
- * map侵入時に必要なデータを全て送りつける
- *------------------------------------------
- */
-void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
-{
-// 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) {
- nullpo_retv(sd);
-
- switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- case 8:
- sd->client_tick = RFIFOL(fd,6);
- break;
- case 9:
- sd->client_tick = RFIFOL(fd,9);
- break;
- case 10:
- sd->client_tick = RFIFOL(fd,7);
- break;
- case 11:
- sd->client_tick = RFIFOL(fd,10);
- break;
- case 12:
- sd->client_tick = RFIFOL(fd,6);
- break;
- case 13:
- sd->client_tick = RFIFOL(fd,5);
- break;
- default: // old version by default (and version 6 + 7)
- sd->client_tick = RFIFOL(fd,2);
- break;
- }
- sd->server_tick = gettick();
- clif_servertick(sd);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_WalkToXY(int fd, struct map_session_data *sd) {
- 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);
-
- switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- case 6:
- x = RFIFOB(fd,5) * 4 + (RFIFOB(fd,6) >> 6);
- y = ((RFIFOB(fd,6) & 0x3f) << 4) + (RFIFOB(fd,7) >> 4);
- break;
- case 7:
- x = RFIFOB(fd,6) * 4 + (RFIFOB(fd,7) >> 6);
- y = ((RFIFOB(fd,7) & 0x3f) << 4) + (RFIFOB(fd,8) >> 4);
- break;
- case 8:
- x = RFIFOB(fd,3) * 4 + (RFIFOB(fd,4) >> 6);
- y = ((RFIFOB(fd,4) & 0x3f) << 4) + (RFIFOB(fd,5) >> 4);
- break;
- case 9:
- x = RFIFOB(fd,12) * 4 + (RFIFOB(fd,13) >> 6);
- y = ((RFIFOB(fd,13) & 0x3f) << 4) + (RFIFOB(fd,14) >> 4);
- break;
- case 10:
- x = RFIFOB(fd,6) * 4 + (RFIFOB(fd,7) >> 6);
- y = ((RFIFOB(fd,7) & 0x3f) << 4) + (RFIFOB(fd,8) >> 4);
- break;
- case 11:
- x = RFIFOB(fd,11) * 4 + (RFIFOB(fd,12) >> 6);
- y = ((RFIFOB(fd,12) & 0x3f) << 4) + (RFIFOB(fd,13) >> 4);
- break;
- case 12:
- x = RFIFOB(fd,3) * 4 + (RFIFOB(fd,4) >> 6);
- y = ((RFIFOB(fd,4) & 0x3f) << 4) + (RFIFOB(fd,5) >> 4);
- break;
- case 13:
- x = RFIFOB(fd,3) * 4 + (RFIFOB(fd,4) >> 6);
- y = ((RFIFOB(fd,4) & 0x3f) << 4) + (RFIFOB(fd,5) >> 4);
- break;
- default: // old version by default
- x = RFIFOB(fd,2) * 4 + (RFIFOB(fd,3) >> 6);
- y = ((RFIFOB(fd,3) & 0x3f) << 4) + (RFIFOB(fd,4) >> 4);
- break;
- }
- pc_walktoxy(sd, x, y);
-
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_QuitGame(int fd, struct map_session_data *sd) {
- 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_len_table[0x18b]);
- 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_len_table[0x18b]);
-
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd) {
- struct block_list *bl;
- int account_id;
-
- switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- case 8:
- account_id = RFIFOL(fd,11);
- break;
- case 9:
- account_id = RFIFOL(fd,8);
- break;
- case 10:
- account_id = RFIFOL(fd,10);
- break;
- case 11:
- account_id = RFIFOL(fd,6);
- break;
- case 12:
- account_id = RFIFOL(fd,11);
- break;
- case 13:
- account_id = RFIFOL(fd,6);
- break;
- default: // old version by default (+ packet version 6 and 7)
- account_id = RFIFOL(fd,2);
- break;
- }
- 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_len_table[0x195]);
- break;
- }
- }
- WFIFOSET(fd,packet_len_table[0x95]);
- }
- break;
- case BL_PET:
- memcpy(WFIFOP(fd,6), ((struct pet_data*)bl)->name, 24);
- WFIFOSET(fd,packet_len_table[0x95]);
- break;
- case BL_NPC:
- memcpy(WFIFOP(fd,6), ((struct npc_data*)bl)->name, 24);
- WFIFOSET(fd,packet_len_table[0x95]);
- 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 && md->guild_id) {
- 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_len_table[0x195]);
- } else {
- WFIFOSET(fd,packet_len_table[0x95]);
- }
- } 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_len_table[0x195]);
- } else {
- WFIFOSET(fd,packet_len_table[0x95]);
- }
- }
- 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) { // S 008c <len>.w <str>.?B
- char *message;
- char *buf;
-
- nullpo_retv(sd);
-
- if ((is_atcommand(fd, sd, RFIFOP(fd,4), 0) != AtCommand_None) ||
- (sd->sc_data &&
- (sd->sc_data[SC_BERSERK].timer != -1 || //バーサーク時は会話も不可
- sd->sc_data[SC_NOCHAT].timer != -1 ))) //チャット禁止
- return;
-
- message = (char*)aCalloc(RFIFOW(fd,2) + 128, sizeof(char));
- buf = (char*)aCalloc(RFIFOW(fd,2) + 4, sizeof(char));
-
- //printf("clif_parse_GlobalMessage: message: '%s'.\n", RFIFOP(fd,4));
- if (strncmp(RFIFOP(fd,4), 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,4)) == 0)
- strcpy(message, " This player sends a void name and a void message.");
- else
- sprintf(message, " This player sends (name:message): '%s'.", RFIFOP(fd,4));
- 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,2));
- WFIFOW(fd,0) = 0x8e;
- WFIFOSET(fd, WFIFOW(fd,2));
-
- if(message) free(message);
- if(buf) 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) {
-// /m /mapmove (as @rura GM command)
- char output[100];
- char map_name[17];
-
- nullpo_retv(sd);
-
- memset(output, '\0', sizeof(output));
- memset(map_name, '\0', sizeof(map_name));
-
- if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) &&
- (pc_isGM(sd) >= get_atcommand_level(AtCommand_MapMove))) {
- memcpy(map_name, RFIFOP(fd,2), 16);
- sprintf(output, "%s %d %d", map_name, RFIFOW(fd,18), RFIFOW(fd,20));
- atcommand_rura(fd, sd, "@rura", output);
- }
-
- return;
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_ChangeDir(int fd, struct map_session_data *sd) {
- unsigned char buf[64];
- short headdir, dir;
-
- nullpo_retv(sd);
-
- switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- case 7:
- headdir = RFIFOW(fd,5);
- dir = RFIFOB(fd,12);
- break;
- case 8:
- headdir = RFIFOW(fd,5);
- dir = RFIFOB(fd,12);
- break;
- case 9:
- headdir = RFIFOW(fd,7);
- dir = RFIFOB(fd,11);
- break;
- case 10:
- headdir = RFIFOW(fd,4);
- dir = RFIFOB(fd,9);
- break;
- case 11:
- headdir = RFIFOW(fd,8);
- dir = RFIFOB(fd,17);
- break;
- case 12:
- headdir = RFIFOW(fd,5);
- dir = RFIFOB(fd,12);
- break;
- case 13:
- headdir = RFIFOW(fd,6);
- dir = RFIFOB(fd,14);
- break;
- default: // old version by default (and packet version 6)
- headdir = RFIFOW(fd,2);
- dir = RFIFOB(fd,4);
- break;
- }
-
- pc_setdir(sd, dir, headdir);
-
- WBUFW(buf,0) = 0x9c;
- WBUFL(buf,2) = sd->bl.id;
- WBUFW(buf,6) = headdir;
- WBUFB(buf,8) = dir;
- if (sd->disguise > 23 && sd->disguise < 4001) // mob disguises [Valaris]
- clif_send(buf, packet_len_table[0x9c], &sd->bl, AREA);
- else
- clif_send(buf, packet_len_table[0x9c], &sd->bl, AREA_WOS);
-
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_Emotion(int fd, struct map_session_data *sd) {
- unsigned char buf[64];
-
- nullpo_retv(sd);
-
- if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, NV_BASIC) >= 2) {
- WBUFW(buf,0) = 0xc0;
- WBUFL(buf,2) = sd->bl.id;
- WBUFB(buf,6) = RFIFOB(fd,2);
- clif_send(buf, packet_len_table[0xc0], &sd->bl, AREA);
- } else
- clif_skill_fail(sd, 1, 0, 1);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_HowManyConnections(int fd, struct map_session_data *sd) {
- WFIFOW(fd,0) = 0xc2;
- WFIFOL(fd,2) = map_getusers();
- WFIFOSET(fd,packet_len_table[0xc2]);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_ActionRequest(int fd, struct map_session_data *sd) {
- 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);
-
- switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- case 8:
- target_id = RFIFOL(fd,3);
- action_type = RFIFOB(fd,8);
- break;
- case 9:
- target_id = RFIFOL(fd,7);
- action_type = RFIFOB(fd,17);
- break;
- case 10:
- target_id = RFIFOL(fd,9);
- action_type = RFIFOB(fd,22);
- break;
- case 11:
- target_id = RFIFOL(fd,3);
- action_type = RFIFOB(fd,8);
- break;
- case 12:
- target_id = RFIFOL(fd,3);
- action_type = RFIFOB(fd,8);
- break;
- case 13:
- target_id = RFIFOL(fd,4);
- action_type = RFIFOB(fd,14);
- break;
- default: // old version by default (and packet version 6 and 7)
- target_id = RFIFOL(fd,2);
- action_type = RFIFOB(fd,6);
- break;
- }
-
- 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(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_len_table[0x8a], &sd->bl, AREA);
- break;
- }
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_Restart(int fd, struct map_session_data *sd) {
- nullpo_retv(sd);
-
- switch(RFIFOB(fd,2)) {
- 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_len_table[0x018b]);
- }
- break;
- }
-}
-
-/*==========================================
- * Transmission of a wisp (S 0096 <len>.w <nick>.24B <message>.?B)
- *------------------------------------------
- */
-void clif_parse_Wis(int fd, struct map_session_data *sd) { // S 0096 <len>.w <nick>.24B <message>.?B // rewritten by [Yor]
- char *gm_command;
- struct map_session_data *dstsd;
- int i;
-
- //printf("clif_parse_Wis: message: '%s'.\n", RFIFOP(fd,28));
-
- gm_command = (char*)aCalloc(strlen(RFIFOP(fd,28)) + 28, sizeof(char)); // 24+3+(RFIFOW(fd,2)-28)+1 or 24+3+(strlen(RFIFOP(fd,28))+1 (size can be wrong with hacker)
-
- sprintf(gm_command, "%s : %s", sd->status.name, RFIFOP(fd,28));
- if ((is_atcommand(fd, sd, gm_command, 0) != AtCommand_None) ||
- (sd && sd->sc_data &&
- (sd->sc_data[SC_BERSERK].timer!=-1 || //バーサーク時は会話も不可
- sd->sc_data[SC_NOCHAT].timer != -1))) //チャット禁止
- {
- if(gm_command) free(gm_command);
- return;
- }
-
- if(gm_command) free(gm_command);
-
- // searching destination character
- dstsd = map_nick2sd(RFIFOP(fd,4));
- // player is not on this map-server
- if (dstsd == NULL ||
- // At this point, don't send wisp/page if it's not exactly the same name, because (example)
- // if there are 'Test' player on an other map-server and 'test' player on this map-server,
- // and if we ask for 'Test', we must not contact 'test' player
- // so, we send information to inter-server, which is the only one which decide (and copy correct name).
- strcmp(dstsd->status.name, RFIFOP(fd,4)) != 0) // not exactly same name
- // send message to inter-server
- intif_wis_message(sd, RFIFOP(fd,4), RFIFOP(fd,28), RFIFOW(fd,2)-28);
- // player is on this map-server
- else {
- // if you send to your self, don't send anything to others
- if (dstsd->fd == fd) // but, normaly, it's impossible!
- clif_wis_message(fd, wisp_server_name, "You can not page yourself. Sorry.", strlen("You can not page yourself. Sorry.") + 1);
- // otherwise, send message and answer immediatly
- else {
- if (dstsd->ignoreAll == 1)
- clif_wis_end(fd, 2); // type: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
- else {
- // if player ignore the source character
- for(i = 0; i < MAX_IGNORE_LIST; i++)
- if (strcmp(dstsd->ignore[i].name, sd->status.name) == 0) {
- clif_wis_end(fd, 2); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
- break;
- }
- // if source player not found in ignore list
- if (i == MAX_IGNORE_LIST) {
- clif_wis_message(dstsd->fd, sd->status.name, RFIFOP(fd,28), RFIFOW(fd,2) - 28);
- clif_wis_end(fd, 0); // type: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
- }
- }
- }
- }
-
- return;
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_GMmessage(int fd, struct map_session_data *sd) {
-// /b
- nullpo_retv(sd);
-
- if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) &&
- (pc_isGM(sd) >= get_atcommand_level(AtCommand_Broadcast)))
- intif_GMmessage(RFIFOP(fd,4), RFIFOW(fd,2)-4, 0);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_TakeItem(int fd, struct map_session_data *sd) {
- struct flooritem_data *fitem;
- int map_object_id;
-
- nullpo_retv(sd);
-
- switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- case 7:
- map_object_id = RFIFOL(fd,6);
- break;
- case 8:
- map_object_id = RFIFOL(fd,6);
- break;
- case 9:
- map_object_id = RFIFOL(fd,9);
- break;
- case 10:
- map_object_id = RFIFOL(fd,7);
- break;
- case 11:
- map_object_id = RFIFOL(fd,10);
- break;
- case 12:
- map_object_id = RFIFOL(fd,6);
- break;
- case 13:
- map_object_id = RFIFOL(fd,5);
- break;
- default: // old version by default (and packet version 6)
- map_object_id = RFIFOL(fd,2);
- break;
- }
- 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 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;
-
- switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- case 8:
- item_index = RFIFOW(fd,5) - 2;
- item_amount = RFIFOW(fd,12);
- break;
- case 9:
- item_index = RFIFOW(fd,8) - 2;
- item_amount = RFIFOW(fd,15);
- break;
- case 10:
- item_index = RFIFOW(fd,6) - 2;
- item_amount = RFIFOW(fd,15);
- break;
- case 11:
- item_index = RFIFOW(fd,12) - 2;
- item_amount = RFIFOW(fd,17);
- break;
- case 12:
- item_index = RFIFOW(fd,5) - 2;
- item_amount = RFIFOW(fd,12);
- break;
- case 13:
- item_index = RFIFOW(fd,6) - 2;
- item_amount = RFIFOW(fd,10);
- break;
- default: // old version by default (+ packet version 6 and 7)
- item_index = RFIFOW(fd,2) - 2;
- item_amount = RFIFOW(fd,4);
- break;
- }
-
- pc_dropitem(sd, item_index, item_amount);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_UseItem(int fd, struct map_session_data *sd) {
- 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);
-
- switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- case 6:
- pc_useitem(sd,RFIFOW(fd,5)-2);
- break;
- case 7:
- pc_useitem(sd,RFIFOW(fd,6)-2);
- break;
- case 8:
- pc_useitem(sd,RFIFOW(fd,6)-2);
- break;
- case 9:
- pc_useitem(sd,RFIFOW(fd,9)-2);
- break;
- case 10:
- pc_useitem(sd,RFIFOW(fd,7)-2);
- break;
- case 11:
- pc_useitem(sd,RFIFOW(fd,10)-2);
- break;
- case 12:
- pc_useitem(sd,RFIFOW(fd,6)-2);
- break;
- case 13:
- pc_useitem(sd,RFIFOW(fd,5)-2);
- break;
- default: // old version by default
- pc_useitem(sd,RFIFOW(fd,2)-2);
- break;
- }
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_EquipItem(int fd,struct map_session_data *sd)
-{
- int index;
-
- nullpo_retv(sd);
-
- if(pc_isdead(sd)) {
- clif_clearchar_area(&sd->bl,1);
- return;
- }
- index = RFIFOW(fd,2)-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,4)=0x8000; // 矢を無理やり装備できるように(−−;
- pc_equipitem(sd,index,RFIFOW(fd,4));
- } else
- pet_equipitem(sd,index);
- }
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_UnequipItem(int fd,struct map_session_data *sd)
-{
- int index;
-
- nullpo_retv(sd);
-
- if(pc_isdead(sd)) {
- clif_clearchar_area(&sd->bl,1);
- return;
- }
- index = RFIFOW(fd,2)-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,index,0);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_NpcClicked(int fd,struct map_session_data *sd)
-{
- 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,2));
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_NpcBuySellSelected(int fd,struct map_session_data *sd)
-{
- npc_buysellsel(sd,RFIFOL(fd,2),RFIFOB(fd,6));
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_NpcBuyListSend(int fd,struct map_session_data *sd)
-{
- int fail=0,n;
- unsigned short *item_list;
-
- n = (RFIFOW(fd,2)-4) /4;
- item_list = (unsigned short*)RFIFOP(fd,4);
-
- fail = npc_buylist(sd,n,item_list);
-
- WFIFOW(fd,0)=0xca;
- WFIFOB(fd,2)=fail;
- WFIFOSET(fd,packet_len_table[0xca]);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_NpcSellListSend(int fd,struct map_session_data *sd)
-{
- int fail=0,n;
- unsigned short *item_list;
-
- n = (RFIFOW(fd,2)-4) /4;
- item_list = (unsigned short*)RFIFOP(fd,4);
-
- fail = npc_selllist(sd,n,item_list);
-
- WFIFOW(fd,0)=0xcb;
- WFIFOB(fd,2)=fail;
- WFIFOSET(fd,packet_len_table[0xcb]);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_CreateChatRoom(int fd,struct map_session_data *sd)
-{
- if(battle_config.basic_skill_check == 0 || pc_checkskill(sd,NV_BASIC) >= 4){
- chat_createchat(sd,RFIFOW(fd,4),RFIFOB(fd,6),RFIFOP(fd,7),RFIFOP(fd,15),RFIFOW(fd,2)-15);
- } else
- clif_skill_fail(sd,1,0,3);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_ChatAddMember(int fd,struct map_session_data *sd)
-{
- chat_joinchat(sd,RFIFOL(fd,2),RFIFOP(fd,6));
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_ChatRoomStatusChange(int fd,struct map_session_data *sd)
-{
- chat_changechatstatus(sd,RFIFOW(fd,4),RFIFOB(fd,6),RFIFOP(fd,7),RFIFOP(fd,15),RFIFOW(fd,2)-15);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_ChangeChatOwner(int fd,struct map_session_data *sd)
-{
- chat_changechatowner(sd,RFIFOP(fd,6));
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_KickFromChat(int fd,struct map_session_data *sd)
-{
- chat_kickchat(sd,RFIFOP(fd,2));
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_ChatLeave(int fd,struct map_session_data *sd)
-{
- chat_leavechat(sd);
-}
-
-/*==========================================
- * 取引要請を相手に送る
- *------------------------------------------
- */
-void clif_parse_TradeRequest(int fd,struct map_session_data *sd)
-{
- nullpo_retv(sd);
-
- if(battle_config.basic_skill_check == 0 || pc_checkskill(sd,NV_BASIC) >= 1){
- trade_traderequest(sd,RFIFOL(sd->fd,2));
- } else
- clif_skill_fail(sd,1,0,0);
-}
-
-/*==========================================
- * 取引要請
- *------------------------------------------
- */
-void clif_parse_TradeAck(int fd,struct map_session_data *sd)
-{
- nullpo_retv(sd);
-
- trade_tradeack(sd,RFIFOB(sd->fd,2));
-}
-
-/*==========================================
- * アイテム追加
- *------------------------------------------
- */
-void clif_parse_TradeAddItem(int fd,struct map_session_data *sd)
-{
- nullpo_retv(sd);
-
- trade_tradeadditem(sd,RFIFOW(sd->fd,2),RFIFOL(sd->fd,4));
-}
-
-/*==========================================
- * アイテム追加完了(ok押し)
- *------------------------------------------
- */
-void clif_parse_TradeOk(int fd,struct map_session_data *sd)
-{
- trade_tradeok(sd);
-}
-
-/*==========================================
- * 取引キャンセル
- *------------------------------------------
- */
-void clif_parse_TradeCansel(int fd,struct map_session_data *sd)
-{
- trade_tradecancel(sd);
-}
-
-/*==========================================
- * 取引許諾(trade押し)
- *------------------------------------------
- */
-void clif_parse_TradeCommit(int fd,struct map_session_data *sd)
-{
- trade_tradecommit(sd);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_StopAttack(int fd,struct map_session_data *sd)
-{
- pc_stopattack(sd);
-}
-
-/*==========================================
- * カートへアイテムを移す
- *------------------------------------------
- */
-void clif_parse_PutItemToCart(int fd,struct map_session_data *sd)
-{
- nullpo_retv(sd);
-
- if(sd->npc_id!=0 || sd->vender_id != 0)
- return;
- pc_putitemtocart(sd,RFIFOW(fd,2)-2,RFIFOL(fd,4));
-}
-/*==========================================
- * カートからアイテムを出す
- *------------------------------------------
- */
-void clif_parse_GetItemFromCart(int fd,struct map_session_data *sd)
-{
- nullpo_retv(sd);
-
- if(sd->npc_id!=0 || sd->vender_id != 0) return;
- pc_getitemfromcart(sd,RFIFOW(fd,2)-2,RFIFOL(fd,4));
-}
-
-/*==========================================
- * 付属品(鷹,ペコ,カート)をはずす
- *------------------------------------------
- */
-void clif_parse_RemoveOption(int fd,struct map_session_data *sd)
-{
- 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)
-{
- pc_setcart(sd,RFIFOW(fd,2));
-}
-
-/*==========================================
- * ステータスアップ
- *------------------------------------------
- */
-void clif_parse_StatusUp(int fd,struct map_session_data *sd)
-{
- pc_statusup(sd,RFIFOW(fd,2));
-}
-
-/*==========================================
- * スキルレベルアップ
- *------------------------------------------
- */
-void clif_parse_SkillUp(int fd,struct map_session_data *sd)
-{
- pc_skillup(sd,RFIFOW(fd,2));
-}
-
-/*==========================================
- * スキル使用(ID指定)
- *------------------------------------------
- */
-void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) {
- 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;
-
- switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- case 6:
- skilllv = RFIFOW(fd,4);
- skillnum = RFIFOW(fd,9);
- target_id = RFIFOL(fd,11);
- break;
- case 7:
- skilllv = RFIFOW(fd,7);
- skillnum = RFIFOW(fd,9);
- target_id = RFIFOL(fd,15);
- break;
- case 8:
- skilllv = RFIFOW(fd,7);
- skillnum = RFIFOW(fd,12);
- target_id = RFIFOL(fd,16);
- break;
- case 9:
- skilllv = RFIFOW(fd,11);
- skillnum = RFIFOW(fd,18);
- target_id = RFIFOL(fd,22);
- break;
- case 10:
- skilllv = RFIFOW(fd,9);
- skillnum = RFIFOW(fd,15);
- target_id = RFIFOL(fd,18);
- break;
- case 11:
- skilllv = RFIFOW(fd,4);
- skillnum = RFIFOW(fd,7);
- target_id = RFIFOL(fd,10);
- break;
- case 12:
- skilllv = RFIFOW(fd,7);
- skillnum = RFIFOW(fd,12);
- target_id = RFIFOL(fd,16);
- break;
- case 13:
- skilllv = RFIFOW(fd,4);
- skillnum = RFIFOW(fd,10);
- target_id = RFIFOL(fd,22);
- break;
- default: // old version by default
- skilllv = RFIFOW(fd,2);
- skillnum = RFIFOW(fd,4);
- target_id = RFIFOL(fd,6);
- break;
- }
-
- 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 skillnum, skilllv, lv, x, y;
- unsigned int tick = gettick();
- int skillmoreinfo;
-
- nullpo_retv(sd);
-
- if (sd->npc_id != 0 || sd->vender_id != 0) return;
- if(sd->chatID) return;
-
- skillmoreinfo = -1;
- switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- case 6:
- skilllv = RFIFOW(fd,4);
- skillnum = RFIFOW(fd,9);
- x = RFIFOW(fd,11);
- y = RFIFOW(fd,13);
- if (RFIFOW(fd,0) == 0x190)
- skillmoreinfo = 15;
- break;
- case 7:
- skilllv = RFIFOW(fd,7);
- skillnum = RFIFOW(fd,9);
- x = RFIFOW(fd,15);
- y = RFIFOW(fd,17);
- if (RFIFOW(fd,0) == 0x190)
- skillmoreinfo = 19;
- break;
- case 8:
- skilllv = RFIFOW(fd,3);
- skillnum = RFIFOW(fd,6);
- x = RFIFOW(fd,17);
- y = RFIFOW(fd,21);
- if (RFIFOW(fd,0) == 0x0a2)
- skillmoreinfo = 23;
- break;
- case 9:
- skilllv = RFIFOW(fd,5);
- skillnum = RFIFOW(fd,15);
- x = RFIFOW(fd,29);
- y = RFIFOW(fd,38);
- if (RFIFOW(fd,0) == 0x0a2)
- skillmoreinfo = 40;
- break;
- case 10:
- skilllv = RFIFOW(fd,10);
- skillnum = RFIFOW(fd,14);
- x = RFIFOW(fd,18);
- y = RFIFOW(fd,23);
- if (RFIFOW(fd,0) == 0x08c)
- skillmoreinfo = 25;
- break;
- case 11:
- skilllv = RFIFOW(fd,6); // 16? to check.
- skillnum = RFIFOW(fd,20);
- x = RFIFOW(fd,23);
- y = RFIFOW(fd,27);
- if (RFIFOW(fd,0) == 0x08c)
- skillmoreinfo = 29;
- break;
- case 12:
- skilllv = RFIFOW(fd,3); // 2? to check.
- skillnum = RFIFOW(fd,6);
- x = RFIFOW(fd,17);
- y = RFIFOW(fd,21);
- if (RFIFOW(fd,0) == 0x08c)
- skillmoreinfo = 23;
- break;
- case 13:
- skilllv = RFIFOW(fd,6);
- skillnum = RFIFOW(fd,9);
- x = RFIFOW(fd,23);
- y = RFIFOW(fd,26);
- if (RFIFOW(fd,0) == 0x08c)
- skillmoreinfo = 28;
- break;
- default: // old version by default
- skilllv = RFIFOW(fd,2);
- skillnum = RFIFOW(fd,4);
- x = RFIFOW(fd,6);
- y = RFIFOW(fd,8);
- if (RFIFOW(fd,0) == 0x190)
- skillmoreinfo = 10;
- break;
- }
-
- if (skillnotok(skillnum, sd))
- return;
-
- if (skillmoreinfo != -1) {
- if (pc_issit(sd)) {
- clif_skill_fail(sd, skillnum, 0, 0);
- return;
- }
- memcpy(talkie_mes, RFIFOP(fd,skillmoreinfo), 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)
-{
- 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,2),RFIFOP(fd,4));
-}
-/*==========================================
- * メモ要求
- *------------------------------------------
- */
-void clif_parse_RequestMemo(int fd,struct map_session_data *sd)
-{
- pc_memo(sd,-1);
-}
-/*==========================================
- * アイテム合成
- *------------------------------------------
- */
-void clif_parse_ProduceMix(int fd,struct map_session_data *sd)
-{
- nullpo_retv(sd);
-
- sd->state.produce_flag = 0;
- skill_produce_mix(sd,RFIFOW(fd,2),RFIFOW(fd,4),RFIFOW(fd,6),RFIFOW(fd,8));
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_NpcSelectMenu(int fd,struct map_session_data *sd)
-{
- nullpo_retv(sd);
-
- sd->npc_menu=RFIFOB(fd,6);
- npc_scriptcont(sd,RFIFOL(fd,2));
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_NpcNextClicked(int fd,struct map_session_data *sd)
-{
- npc_scriptcont(sd,RFIFOL(fd,2));
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_NpcAmountInput(int fd,struct map_session_data *sd)
-{
- 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,6); //fixed by Lupus. npc_amount is (int) but was RFIFOL changing it to (unsigned int)
-
-#undef RFIFOL_
-
- npc_scriptcont(sd,RFIFOL(fd,2));
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_NpcStringInput(int fd,struct map_session_data *sd)
-{
- nullpo_retv(sd);
-
- if(RFIFOW(fd,2)-7 >= sizeof(sd->npc_str)){
- printf("clif: input string too long !\n");
- memcpy(sd->npc_str,RFIFOP(fd,8),sizeof(sd->npc_str));
- sd->npc_str[sizeof(sd->npc_str)-1]=0;
- } else
- strcpy(sd->npc_str,RFIFOP(fd,8));
- npc_scriptcont(sd,RFIFOL(fd,4));
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void clif_parse_NpcCloseClicked(int fd,struct map_session_data *sd)
-{
- npc_scriptcont(sd,RFIFOL(fd,2));
-}
-
-/*==========================================
- * アイテム鑑定
- *------------------------------------------
- */
-void clif_parse_ItemIdentify(int fd,struct map_session_data *sd)
-{
- pc_item_identify(sd,RFIFOW(fd,2)-2);
-}
-/*==========================================
- * 矢作成
- *------------------------------------------
- */
-void clif_parse_SelectArrow(int fd,struct map_session_data *sd)
-{
- nullpo_retv(sd);
-
- sd->state.make_arrow_flag = 0;
- skill_arrow_create(sd,RFIFOW(fd,2));
-}
-/*==========================================
- * オートスペル受信
- *------------------------------------------
- */
-void clif_parse_AutoSpell(int fd,struct map_session_data *sd)
-{
- skill_autospell(sd,RFIFOW(fd,2));
-}
-/*==========================================
- * カード使用
- *------------------------------------------
- */
-void clif_parse_UseCard(int fd,struct map_session_data *sd)
-{
- clif_use_card(sd,RFIFOW(fd,2)-2);
-}
-/*==========================================
- * カード挿入装備選択
- *------------------------------------------
- */
-void clif_parse_InsertCard(int fd,struct map_session_data *sd)
-{
- pc_insert_card(sd,RFIFOW(fd,2)-2,RFIFOW(fd,4)-2);
-}
-
-/*==========================================
- * 0193 キャラID名前引き
- *------------------------------------------
- */
-void clif_parse_SolveCharName(int fd, struct map_session_data *sd) {
- int char_id;
-
- switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- case 8:
- char_id = RFIFOL(fd,8);
- break;
- case 9:
- char_id = RFIFOL(fd,7);
- break;
- case 10:
- char_id = RFIFOL(fd,10);
- break;
- case 11:
- char_id = RFIFOL(fd,6);
- break;
- case 12:
- char_id = RFIFOL(fd,8);
- break;
- case 13:
- char_id = RFIFOL(fd,12);
- break;
- default: // old version by default (+ packet version 6 and 7)
- char_id = RFIFOL(fd,2);
- break;
- }
- clif_solved_charname(sd, char_id);
-}
-
-/*==========================================
- * 0197 /resetskill /resetstate
- *------------------------------------------
- */
-void clif_parse_ResetChar(int fd, struct map_session_data *sd) {
- nullpo_retv(sd);
-
- if (battle_config.atc_gmonly == 0 || pc_isGM(sd)) {
- switch(RFIFOW(fd,2)){
- case 0:
- if (pc_isGM(sd) >= get_atcommand_level(AtCommand_ResetState))
- pc_resetstate(sd);
- break;
- case 1:
- if (pc_isGM(sd) >= get_atcommand_level(AtCommand_ResetState))
- pc_resetskill(sd);
- break;
- }
- }
-}
-
-/*==========================================
- * 019c /lb等
- *------------------------------------------
- */
-void clif_parse_LGMmessage(int fd, struct map_session_data *sd) {
- 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) = RFIFOW(fd,2);
- memcpy(WBUFP(buf,4), RFIFOP(fd,4), RFIFOW(fd,2) - 4);
- clif_send(buf, RFIFOW(fd,2), &sd->bl, ALL_SAMEMAP);
- }
-}
-
-/*==========================================
- * カプラ倉庫へ入れる
- *------------------------------------------
- */
-void clif_parse_MoveToKafra(int fd, struct map_session_data *sd) {
- int item_index, item_amount;
-
- nullpo_retv(sd);
-
- if (sd->npc_id != 0 || sd->vender_id != 0)
- return;
-
- switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- case 8:
- item_index = RFIFOW(fd,5) - 2;
- item_amount = RFIFOL(fd,12);
- break;
- case 9:
- item_index = RFIFOW(fd,5) - 2;
- item_amount = RFIFOL(fd,19);
- break;
- case 10:
- item_index = RFIFOW(fd,3) - 2;
- item_amount = RFIFOL(fd,15);
- break;
- case 11:
- item_index = RFIFOW(fd,6) - 2;
- item_amount = RFIFOL(fd,21);
- break;
- case 12:
- item_index = RFIFOW(fd,5) - 2;
- item_amount = RFIFOL(fd,12);
- break;
- case 13:
- item_index = RFIFOW(fd,6) - 2;
- item_amount = RFIFOL(fd,9);
- break;
- default: // old version by default (+ packet version 6 and 7)
- item_index = RFIFOW(fd,2) - 2;
- item_amount = RFIFOL(fd,4);
- break;
- }
-
- if (item_index < 0 || item_index >= MAX_INVENTORY)
- return;
-
- 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 item_index, item_amount;
-
- nullpo_retv(sd);
-
- switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- case 8:
- item_index = RFIFOW(fd,10) - 1;
- item_amount = RFIFOL(fd,22);
- break;
- case 9:
- item_index = RFIFOW(fd,11) - 1;
- item_amount = RFIFOL(fd,22);
- break;
- case 10:
- item_index = RFIFOW(fd,3) - 1;
- item_amount = RFIFOL(fd,13);
- break;
- case 11:
- item_index = RFIFOW(fd,4) - 1;
- item_amount = RFIFOL(fd,8);
- break;
- case 12:
- item_index = RFIFOW(fd,10) - 1;
- item_amount = RFIFOL(fd,22);
- break;
- case 13:
- item_index = RFIFOW(fd,12) - 1;
- item_amount = RFIFOL(fd,18);
- break;
- default: // old version by default (+ packet version 6 and 7)
- item_index = RFIFOW(fd,2) - 1;
- item_amount = RFIFOL(fd,4);
- break;
- }
-
- if (sd->npc_id != 0 || sd->vender_id != 0)
- return;
-
- 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) {
- 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,2) - 2, RFIFOL(fd,4));
- else
- storage_storageaddfromcart(sd, RFIFOW(fd,2) - 2, RFIFOL(fd,4));
-}
-
-/*==========================================
- * カプラ倉庫から出す
- *------------------------------------------
- */
-void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd) {
- nullpo_retv(sd);
-
- if (sd->npc_id != 0 || sd->vender_id != 0)
- return;
- if (sd->state.storage_flag)
- storage_guild_storagegettocart(sd, RFIFOW(fd,2)-1, RFIFOL(fd,4));
- else
- storage_storagegettocart(sd, RFIFOW(fd,2)-1, RFIFOL(fd,4));
-}
-
-/*==========================================
- * カプラ倉庫を閉じる
- *------------------------------------------
- */
-void clif_parse_CloseKafra(int fd, struct map_session_data *sd) {
- 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) {
- if (battle_config.basic_skill_check == 0 || pc_checkskill(sd,NV_BASIC) >= 7) {
- party_create(sd,RFIFOP(fd,2));
- } else
- clif_skill_fail(sd,1,0,4);
-}
-
-/*==========================================
- * パーティを作る
- *------------------------------------------
- */
-void clif_parse_CreateParty2(int fd, struct map_session_data *sd) {
- if (battle_config.basic_skill_check == 0 || pc_checkskill(sd,NV_BASIC) >= 7){
- party_create(sd, RFIFOP(fd,2));
- } else
- clif_skill_fail(sd, 1, 0, 4);
-}
-
-/*==========================================
- * パーティに勧誘
- *------------------------------------------
- */
-void clif_parse_PartyInvite(int fd, struct map_session_data *sd) {
- party_invite(sd, RFIFOL(fd,2));
-}
-
-/*==========================================
- * パーティ勧誘返答
- *------------------------------------------
- */
-void clif_parse_ReplyPartyInvite(int fd,struct map_session_data *sd) {
- if(battle_config.basic_skill_check == 0 || pc_checkskill(sd,NV_BASIC) >= 5){
- party_reply_invite(sd,RFIFOL(fd,2),RFIFOL(fd,6));
- } else {
- party_reply_invite(sd,RFIFOL(fd,2),-1);
- clif_skill_fail(sd,1,0,4);
- }
-}
-
-/*==========================================
- * パーティ脱退要求
- *------------------------------------------
- */
-void clif_parse_LeaveParty(int fd, struct map_session_data *sd) {
- party_leave(sd);
-}
-
-/*==========================================
- * パーティ除名要求
- *------------------------------------------
- */
-void clif_parse_RemovePartyMember(int fd, struct map_session_data *sd) {
- party_removemember(sd,RFIFOL(fd,2),RFIFOP(fd,6));
-}
-
-/*==========================================
- * パーティ設定変更要求
- *------------------------------------------
- */
-void clif_parse_PartyChangeOption(int fd, struct map_session_data *sd) {
- party_changeoption(sd, RFIFOW(fd,2), RFIFOW(fd,4));
-}
-
-/*==========================================
- * パーティメッセージ送信要求
- *------------------------------------------
- */
-void clif_parse_PartyMessage(int fd, struct map_session_data *sd) {
- nullpo_retv(sd);
-
- if (is_atcommand(fd, sd, RFIFOP(fd,4), 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,4), RFIFOW(fd,2)-4);
-}
-
-/*==========================================
- * 露店閉鎖
- *------------------------------------------
- */
-void clif_parse_CloseVending(int fd, struct map_session_data *sd) {
- vending_closevending(sd);
-}
-
-/*==========================================
- * 露店アイテムリスト要求
- *------------------------------------------
- */
-void clif_parse_VendingListReq(int fd, struct map_session_data *sd) {
- nullpo_retv(sd);
-
- vending_vendinglistreq(sd,RFIFOL(fd,2));
- if(sd->npc_id)
- npc_event_dequeue(sd);
-}
-
-/*==========================================
- * 露店アイテム購入
- *------------------------------------------
- */
-void clif_parse_PurchaseReq(int fd, struct map_session_data *sd) {
- vending_purchasereq(sd, RFIFOW(fd,2), RFIFOL(fd,4), RFIFOP(fd,8));
-}
-
-/*==========================================
- * 露店開設
- *------------------------------------------
- */
-void clif_parse_OpenVending(int fd,struct map_session_data *sd) {
- vending_openvending(sd, RFIFOW(fd,2), RFIFOP(fd,4), RFIFOB(fd,84), RFIFOP(fd,85));
-}
-
-/*==========================================
- * /monster /item rewriten by [Yor]
- *------------------------------------------
- */
-void clif_parse_GM_Monster_Item(int fd, struct map_session_data *sd) {
- char monster_item_name[25];
-
- nullpo_retv(sd);
-
- memset(monster_item_name, '\0', sizeof(monster_item_name));
-
- if (battle_config.atc_gmonly == 0 || pc_isGM(sd)) {
- memcpy(monster_item_name, RFIFOP(fd,2), 24);
-
- if (mobdb_searchname(monster_item_name) != 0) {
- if (pc_isGM(sd) >= get_atcommand_level(AtCommand_Monster))
- atcommand_spawn(fd, sd, "@spawn", monster_item_name); // as @spawn
- } else if (itemdb_searchname(monster_item_name) != NULL) {
- if (pc_isGM(sd) >= get_atcommand_level(AtCommand_Item))
- atcommand_item(fd, sd, "@item", monster_item_name); // as @item
- }
-
- }
-}
-
-/*==========================================
- * ギルドを作る
- *------------------------------------------
- */
-void clif_parse_CreateGuild(int fd,struct map_session_data *sd) {
- guild_create(sd, RFIFOP(fd,6));
-}
-
-/*==========================================
- * ギルドマスターかどうか確認
- *------------------------------------------
- */
-void clif_parse_GuildCheckMaster(int fd, struct map_session_data *sd) {
- clif_guild_masterormember(sd);
-}
-
-/*==========================================
- * ギルド情報要求
- *------------------------------------------
- */
-void clif_parse_GuildReqeustInfo(int fd, struct map_session_data *sd) {
- switch(RFIFOL(fd,2)){
- 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,2));
- break;
- }
-}
-
-/*==========================================
- * ギルド役職変更
- *------------------------------------------
- */
-void clif_parse_GuildChangePositionInfo(int fd, struct map_session_data *sd) {
- int i;
-
- for(i = 4; i < RFIFOW(fd,2); 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 i;
-
- nullpo_retv(sd);
-
- for(i=4;i<RFIFOW(fd,2);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) {
- struct guild *g=guild_search(RFIFOL(fd,2));
- if(g!=NULL)
- clif_guild_emblem(sd,g);
-}
-
-/*==========================================
- * ギルドエンブレム変更
- *------------------------------------------
- */
-void clif_parse_GuildChangeEmblem(int fd,struct map_session_data *sd) {
- guild_change_emblem(sd,RFIFOW(fd,2)-4,RFIFOP(fd,4));
-}
-
-/*==========================================
- * ギルド告知変更
- *------------------------------------------
- */
-void clif_parse_GuildChangeNotice(int fd,struct map_session_data *sd) {
- guild_change_notice(sd,RFIFOL(fd,2),RFIFOP(fd,6),RFIFOP(fd,66));
-}
-
-/*==========================================
- * ギルド勧誘
- *------------------------------------------
- */
-void clif_parse_GuildInvite(int fd,struct map_session_data *sd) {
- guild_invite(sd,RFIFOL(fd,2));
-}
-
-/*==========================================
- * ギルド勧誘返信
- *------------------------------------------
- */
-void clif_parse_GuildReplyInvite(int fd,struct map_session_data *sd) {
- guild_reply_invite(sd,RFIFOL(fd,2),RFIFOB(fd,6));
-}
-
-/*==========================================
- * ギルド脱退
- *------------------------------------------
- */
-void clif_parse_GuildLeave(int fd,struct map_session_data *sd) {
- guild_leave(sd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOP(fd,14));
-}
-
-/*==========================================
- * ギルド追放
- *------------------------------------------
- */
-void clif_parse_GuildExplusion(int fd,struct map_session_data *sd) {
- guild_explusion(sd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOP(fd,14));
-}
-
-/*==========================================
- * ギルド会話
- *------------------------------------------
- */
-void clif_parse_GuildMessage(int fd,struct map_session_data *sd) {
- nullpo_retv(sd);
-
- if (is_atcommand(fd, sd, RFIFOP(fd, 4), 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,4), RFIFOW(fd,2)-4);
-}
-
-/*==========================================
- * ギルド同盟要求
- *------------------------------------------
- */
-void clif_parse_GuildRequestAlliance(int fd, struct map_session_data *sd) {
- guild_reqalliance(sd,RFIFOL(fd,2));
-}
-
-/*==========================================
- * ギルド同盟要求返信
- *------------------------------------------
- */
-void clif_parse_GuildReplyAlliance(int fd, struct map_session_data *sd) {
- guild_reply_reqalliance(sd,RFIFOL(fd,2),RFIFOL(fd,6));
-}
-
-/*==========================================
- * ギルド関係解消
- *------------------------------------------
- */
-void clif_parse_GuildDelAlliance(int fd, struct map_session_data *sd) {
- guild_delalliance(sd,RFIFOL(fd,2),RFIFOL(fd,6));
-}
-
-/*==========================================
- * ギルド敵対
- *------------------------------------------
- */
-void clif_parse_GuildOpposition(int fd, struct map_session_data *sd) {
- guild_opposition(sd,RFIFOL(fd,2));
-}
-
-/*==========================================
- * ギルド解散
- *------------------------------------------
- */
-void clif_parse_GuildBreak(int fd, struct map_session_data *sd) {
- guild_break(sd,RFIFOP(fd,2));
-}
-
-// pet
-void clif_parse_PetMenu(int fd, struct map_session_data *sd) {
- pet_menu(sd,RFIFOB(fd,2));
-}
-
-void clif_parse_CatchPet(int fd, struct map_session_data *sd) {
- pet_catch_process2(sd,RFIFOL(fd,2));
-}
-
-void clif_parse_SelectEgg(int fd, struct map_session_data *sd) {
- pet_select_egg(sd,RFIFOW(fd,2)-2);
-}
-
-void clif_parse_SendEmotion(int fd, struct map_session_data *sd) {
- nullpo_retv(sd);
-
- if(sd->pd)
- clif_pet_emotion(sd->pd,RFIFOL(fd,2));
-}
-
-void clif_parse_ChangePetName(int fd, struct map_session_data *sd) {
- pet_change_name(sd,RFIFOP(fd,2));
-}
-
-// Kick (right click menu for GM "(name) force to quit")
-void clif_parse_GMKick(int fd, struct map_session_data *sd) {
- struct block_list *target;
- int tid = RFIFOL(fd,2);
-
- 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);
- }
-}
-
-/*==========================================
- * /shift
- *------------------------------------------
- */
-void clif_parse_Shift(int fd, struct map_session_data *sd) { // Rewriten by [Yor]
- char player_name[25];
-
- nullpo_retv(sd);
-
- memset(player_name, '\0', sizeof(player_name));
-
- if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) &&
- (pc_isGM(sd) >= get_atcommand_level(AtCommand_JumpTo))) {
- memcpy(player_name, RFIFOP(fd,2), 24);
- atcommand_jumpto(fd, sd, "@jumpto", player_name); // as @jumpto
- }
-
- return;
-}
-
-/*==========================================
- * /recall
- *------------------------------------------
- */
-void clif_parse_Recall(int fd, struct map_session_data *sd) { // Added by RoVeRT
- char player_name[25];
-
- nullpo_retv(sd);
-
- memset(player_name, '\0', sizeof(player_name));
-
- if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) &&
- (pc_isGM(sd) >= get_atcommand_level(AtCommand_Recall))) {
- memcpy(player_name, RFIFOP(fd,2), 24);
- atcommand_recall(fd, sd, "@recall", player_name); // as @recall
- }
-
- return;
-}
-
-void clif_parse_GMHide(int fd, struct map_session_data *sd) { // Modified by [Yor]
- nullpo_retv(sd);
-
- //printf("%2x %2x %2x\n", RFIFOW(fd,0), RFIFOW(fd,2), RFIFOW(fd,4)); // R 019d <Option_value>.2B <flag>.2B
- if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) &&
- (pc_isGM(sd) >= get_atcommand_level(AtCommand_Hide))) {
- if (sd->status.option & OPTION_HIDE) { // OPTION_HIDE = 0x40
- sd->status.option &= ~OPTION_HIDE; // OPTION_HIDE = 0x40
- clif_displaymessage(fd, "Invisible: Off.");
- } else {
- sd->status.option |= OPTION_HIDE; // OPTION_HIDE = 0x40
- clif_displaymessage(fd, "Invisible: On.");
- }
- clif_changeoption(&sd->bl);
- }
-}
-
-/*==========================================
- * GMによるチャット禁止時間付与
- *------------------------------------------
- */
-void clif_parse_GMReqNoChat(int fd,struct map_session_data *sd)
-{
- int tid = RFIFOL(fd,2);
- int type = RFIFOB(fd,6);
- int limit = RFIFOW(fd,7);
- 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_len_table[0x14b]);
- 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 tid = RFIFOL(fd,2);
-
- WFIFOW(fd,0) = 0x1e0;
- WFIFOL(fd,2) = tid;
- sprintf(WFIFOP(fd,6),"%d",tid);
-// memcpy(WFIFOP(fd,6), "TESTNAME", 24);
- WFIFOSET(fd, packet_len_table[0x1e0]);
-
- return;
-}
-
-void clif_parse_PMIgnore(int fd, struct map_session_data *sd) { // Rewritten by [Yor]
- char output[512];
- char *nick; // S 00cf <nick>.24B <type>.B: 00 (/ex nick) deny speech from nick, 01 (/in nick) allow speech from nick
- int i, pos;
-
- memset(output, '\0', sizeof(output));
-
- nick = RFIFOP(fd,2); // speed up
- RFIFOB(fd,25) = '\0'; // to be sure that the player name have at maximum 23 characters
- //printf("Ignore: char '%s' state: %d\n", nick, RFIFOB(fd,26));
-
- WFIFOW(fd,0) = 0x0d1; // R 00d1 <type>.B <fail>.B: type: 0: deny, 1: allow, fail: 0: success, 1: fail
- WFIFOB(fd,2) = RFIFOB(fd,26);
- // do nothing only if nick can not exist
- if (strlen(nick) < 4) {
- WFIFOB(fd,3) = 1; // fail
- WFIFOSET(fd, packet_len_table[0x0d1]);
- if (RFIFOB(fd,26) == 0) // type
- clif_wis_message(fd, wisp_server_name, "It's impossible to block this player.", strlen("It's impossible to block this player.") + 1);
- else
- clif_wis_message(fd, wisp_server_name, "It's impossible to unblock this player.", strlen("It's impossible to unblock this player.") + 1);
- return;
- // name can exist
- } else {
- // deny action (we add nick only if it's not already exist
- if (RFIFOB(fd,26) == 0) { // type
- pos = -1;
- for(i = 0; i < MAX_IGNORE_LIST; i++) {
- if (strcmp(sd->ignore[i].name, nick) == 0) {
- WFIFOB(fd,3) = 1; // fail
- WFIFOSET(fd, packet_len_table[0x0d1]);
- clif_wis_message(fd, wisp_server_name, "This player is already blocked.", strlen("This player is already blocked.") + 1);
- if (strcmp(wisp_server_name, nick) == 0) { // to found possible bot users who automaticaly ignore people.
- sprintf(output, "Character '%s' (account: %d) has tried AGAIN to block wisps from '%s' (wisp name of the server). Bot user?", sd->status.name, sd->status.account_id, wisp_server_name);
- intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, output, strlen(output) + 1);
- }
- return;
- } else if (pos == -1 && sd->ignore[i].name[0] == '\0')
- pos = i;
- }
- // if a position is found and name not found, we add it in the list
- if (pos != -1) {
- memcpy(sd->ignore[pos].name, nick, 24);
- WFIFOB(fd,3) = 0; // success
- WFIFOSET(fd, packet_len_table[0x0d1]);
- if (strcmp(wisp_server_name, nick) == 0) { // to found possible bot users who automaticaly ignore people.
- sprintf(output, "Character '%s' (account: %d) has tried to block wisps from '%s' (wisp name of the server). Bot user?", sd->status.name, sd->status.account_id, wisp_server_name);
- intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, output, strlen(output) + 1);
- // send something to be inform and force bot to ignore twice... If GM receiving block + block again, it's a bot :)
- clif_wis_message(fd, wisp_server_name, "Add me in your ignore list, doesn't block my wisps.", strlen("Add me in your ignore list, doesn't block my wisps.") + 1);
- }
- } else {
- WFIFOB(fd,3) = 1; // fail
- WFIFOSET(fd, packet_len_table[0x0d1]);
- clif_wis_message(fd, wisp_server_name, "You can not block more people.", strlen("You can not block more people.") + 1);
- if (strcmp(wisp_server_name, nick) == 0) { // to found possible bot users who automaticaly ignore people.
- sprintf(output, "Character '%s' (account: %d) has tried to block wisps from '%s' (wisp name of the server). Bot user?", sd->status.name, sd->status.account_id, wisp_server_name);
- intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, output, strlen(output) + 1);
- }
- }
- // allow action (we remove all same nicks if they exist)
- } else {
- pos = -1;
- for(i = 0; i < MAX_IGNORE_LIST; i++)
- if (strcmp(sd->ignore[i].name, nick) == 0) {
- memset(sd->ignore[i].name, 0, sizeof(sd->ignore[i].name));
- if (pos != -1) {
- WFIFOB(fd,3) = 0; // success
- WFIFOSET(fd, packet_len_table[0x0d1]);
- pos = i; // don't break, to remove ALL same nick
- }
- }
- if (pos == -1) {
- WFIFOB(fd,3) = 1; // fail
- WFIFOSET(fd, packet_len_table[0x0d1]);
- clif_wis_message(fd, wisp_server_name, "This player is not blocked by you.", strlen("This player is not blocked by you.") + 1);
- }
- }
- }
-
-// for(i = 0; i < MAX_IGNORE_LIST; i++) // for debug only
-// if (sd->ignore[i].name[0] != '\0')
-// printf("Ignored player: '%s'\n", sd->ignore[i].name);
-
- return;
-}
-
-void clif_parse_PMIgnoreAll(int fd, struct map_session_data *sd) { // Rewritten by [Yor]
- //printf("Ignore all: state: %d\n", RFIFOB(fd,2));
- if (RFIFOB(fd,2) == 0) {// S 00d0 <type>len.B: 00 (/exall) deny all speech, 01 (/inall) allow all speech
- WFIFOW(fd,0) = 0x0d2; // R 00d2 <type>.B <fail>.B: type: 0: deny, 1: allow, fail: 0: success, 1: fail
- WFIFOB(fd,2) = 0;
- if (sd->ignoreAll == 0) {
- sd->ignoreAll = 1;
- WFIFOB(fd,3) = 0; // success
- WFIFOSET(fd, packet_len_table[0x0d2]);
- } else {
- WFIFOB(fd,3) = 1; // fail
- WFIFOSET(fd, packet_len_table[0x0d2]);
- clif_wis_message(fd, wisp_server_name, "You already block everyone.", strlen("You already block everyone.") + 1);
- }
- } else {
- WFIFOW(fd,0) = 0x0d2; // R 00d2 <type>.B <fail>.B: type: 0: deny, 1: allow, fail: 0: success, 1: fail
- WFIFOB(fd,2) = 1;
- if (sd->ignoreAll == 1) {
- sd->ignoreAll = 0;
- WFIFOB(fd,3) = 0; // success
- WFIFOSET(fd, packet_len_table[0x0d2]);
- } else {
- WFIFOB(fd,3) = 1; // fail
- WFIFOSET(fd, packet_len_table[0x0d2]);
- clif_wis_message(fd, wisp_server_name, "You already allow everyone.", strlen("You already allow everyone.") + 1);
- }
- }
-
- return;
-}
-
-void clif_parse_skillMessage(int fd, struct map_session_data *sd) { // Added by RoVeRT
- int skillid,skilllv, x, y;
- char *mes;
-
- skilllv = RFIFOW(fd,2);
- skillid = RFIFOW(fd,4);
-
- y = RFIFOB(fd,6);
- x = RFIFOB(fd,8);
-
- mes = RFIFOP(fd,10);
-
- // skill 220 = graffiti
-// printf("skill: %d %d location: %3d %3d message: %s\n", skillid, skilllv, x, y, (char*)mes);
-}
-
-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_len_table[0x1d1]);
-
- return 0;
-}
-
-/*==========================================
- * スパノビの/doridoriによるSPR2倍
- *------------------------------------------
- */
-void clif_parse_sn_doridori(int fd, struct map_session_data *sd) {
- if (sd)
- sd->doridori_counter = 1;
-
- return;
-}
-/*==========================================
- * スパノビの爆裂波動
- *------------------------------------------
- */
-void clif_parse_sn_explosionspirits(int fd, struct map_session_data *sd)
-{
- 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
- *------------------------------------------
- */
-void clif_friends_list_send(struct map_session_data *sd) {
- int i, n;
-
- // Send friends list
- n = 0;
- WFIFOW(sd->fd, 0) = 0x201;
- for(i = 0; i < 20; i++)
- if (sd->status.friend_id[i]) {
- WFIFOL(sd->fd,4 + 32 * n + 1) = sd->status.friend_id[i];
- //WFIFOB(sd->fd,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(WFIFOP(sd->fd,4 + 32 * n + 8), &sd->status.friend_name[i], 23);
- n++;
- }
- WFIFOW(sd->fd,2) = 4 + 32 * n;
- WFIFOSET(sd->fd, WFIFOW(sd->fd,2));
-}
-
-void clif_parse_friends_list_add(int fd, struct map_session_data *sd) {
- struct map_session_data *f_sd;
- int i;
-
- f_sd = map_nick2sd(RFIFOP(fd,2));
-
- // Friend doesn't exist (no player with this name)
- if (f_sd == NULL) {
- clif_displaymessage(fd, "This name (for a friend) doesn't exist.");
- return;
- }
-
- // Friend already exists
- for (i = 0; i < 20; i++)
- if (sd->status.friend_id[i] == f_sd->status.char_id) {
- clif_displaymessage(fd, "Friend already exists.");
- return;
- }
-
- // Find an empty slot
- for (i = 0; i < 20; i++)
- if (sd->status.friend_id[i] == 0)
- break;
- if (i == 20) {
- clif_displaymessage(fd, "Friends list is full.");
- return;
- }
-
- sd->status.friend_id[i] = f_sd->status.char_id;
- memset(sd->status.friend_name[i], 0, sizeof(sd->status.friend_name[i]));
- memcpy(sd->status.friend_name[i], f_sd->status.name, 23);
- clif_displaymessage(fd, "Friend added.");
-
- clif_friends_list_send(sd);
-
- //printf("clif_parse_friends_list_add");
-
- return;
-}
-
-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);
- int i, j;
-
- // Search friend
- for (i = 0; i < 20; i ++)
- if (sd->status.friend_id[i] == id) {
- // move all chars down
- for(j = i + 1; j < 20; j++) {
- sd->status.friend_id[j-1] = sd->status.friend_id[j];
- memcpy(sd->status.friend_name[j-1], sd->status.friend_name[j], sizeof(sd->status.friend_name[j]));
- }
- sd->status.friend_id[19] = 0;
- memset(sd->status.friend_name[19], 0, sizeof(sd->status.friend_name[19]));
- clif_displaymessage(fd, "Friend removed");
- clif_friends_list_send(sd);
- break;
- }
-
- if (i == 20)
- clif_displaymessage(fd, "Name not found in list.");
-
- return;
-}
-
-/*==========================================
- * /killall
- *------------------------------------------
- */
-void clif_parse_GMkillall(int fd,struct map_session_data *sd)
-{
- char message[50];
-
- nullpo_retv(sd);
-
- strncpy(message,sd->status.name, 24);
- is_atcommand(fd, sd, strcat(message," : @kickall"),0);
-
- return;
-}
-
-// functions list
-static void (*clif_parse_func_table[7][0x220])() = {
- {
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
- // 40
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
- // 70
- NULL, NULL, clif_parse_WantToConnection, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, clif_parse_LoadEndAck, clif_parse_TickSend, NULL,
-
- // 80
- NULL, NULL, NULL, NULL, NULL, clif_parse_WalkToXY, NULL, NULL,
- NULL, clif_parse_ActionRequest, NULL, NULL, clif_parse_GlobalMessage, NULL, NULL, NULL,
- // 90
- clif_parse_NpcClicked, NULL, NULL, NULL, clif_parse_GetCharNameRequest, NULL, clif_parse_Wis, NULL,
- NULL, clif_parse_GMmessage, NULL, clif_parse_ChangeDir, NULL, NULL, NULL, clif_parse_TakeItem,
- // a0
- NULL, NULL, clif_parse_DropItem, NULL, NULL, NULL, NULL, clif_parse_UseItem,
- NULL, clif_parse_EquipItem, NULL, clif_parse_UnequipItem, NULL, NULL, NULL, NULL,
- // b0
- NULL, NULL, clif_parse_Restart, NULL, NULL, NULL, NULL, NULL,
- clif_parse_NpcSelectMenu, clif_parse_NpcNextClicked, NULL, clif_parse_StatusUp, NULL, NULL, NULL, clif_parse_Emotion,
-
- // c0
- NULL, clif_parse_HowManyConnections, NULL, NULL, NULL, clif_parse_NpcBuySellSelected, NULL, NULL,
- clif_parse_NpcBuyListSend, clif_parse_NpcSellListSend, NULL, NULL, clif_parse_GMKick, NULL, clif_parse_GMkillall, clif_parse_PMIgnore,
- // d0
- clif_parse_PMIgnoreAll, NULL, NULL, NULL, NULL, clif_parse_CreateChatRoom, NULL, NULL,
- NULL, clif_parse_ChatAddMember, NULL, NULL, NULL, NULL, clif_parse_ChatRoomStatusChange, NULL,
- // e0
- clif_parse_ChangeChatOwner, NULL, clif_parse_KickFromChat, clif_parse_ChatLeave, clif_parse_TradeRequest, NULL, clif_parse_TradeAck, NULL,
- clif_parse_TradeAddItem, NULL, NULL, clif_parse_TradeOk, NULL, clif_parse_TradeCansel, NULL, clif_parse_TradeCommit,
- // f0
- NULL, NULL, NULL, clif_parse_MoveToKafra, NULL, clif_parse_MoveFromKafra, NULL, clif_parse_CloseKafra,
- NULL, clif_parse_CreateParty, NULL, NULL, clif_parse_PartyInvite, NULL, NULL, clif_parse_ReplyPartyInvite,
-
- // 100
- clif_parse_LeaveParty, NULL, clif_parse_PartyChangeOption, clif_parse_RemovePartyMember, NULL, NULL, NULL, NULL,
- clif_parse_PartyMessage, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- // 110
- NULL, NULL, clif_parse_SkillUp, clif_parse_UseSkillToId, NULL, NULL, clif_parse_UseSkillToPos, NULL,
- clif_parse_StopAttack, NULL, NULL, clif_parse_UseSkillMap, NULL, clif_parse_RequestMemo, NULL, NULL,
- // 120
- NULL, NULL, NULL, NULL, NULL, NULL, clif_parse_PutItemToCart, clif_parse_GetItemFromCart,
- clif_parse_MoveFromKafraToCart, clif_parse_MoveToKafraFromCart, clif_parse_RemoveOption, NULL, NULL, NULL, clif_parse_CloseVending, NULL,
- // 130
- clif_parse_VendingListReq, NULL, NULL, NULL, clif_parse_PurchaseReq, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, clif_parse_GM_Monster_Item,
-
- // 140
- clif_parse_MapMove, NULL, NULL, clif_parse_NpcAmountInput, NULL, NULL, clif_parse_NpcCloseClicked, NULL,
- NULL, clif_parse_GMReqNoChat, NULL, NULL, NULL, clif_parse_GuildCheckMaster, NULL, clif_parse_GuildReqeustInfo,
- // 150
- NULL, clif_parse_GuildRequestEmblem, NULL, clif_parse_GuildChangeEmblem, NULL, clif_parse_GuildChangeMemberPosition, NULL, NULL,
- NULL, clif_parse_GuildLeave, NULL, clif_parse_GuildExplusion, NULL, clif_parse_GuildBreak, NULL, NULL,
- // 160
- NULL, clif_parse_GuildChangePositionInfo, NULL, NULL, NULL, clif_parse_CreateGuild, NULL, NULL,
- clif_parse_GuildInvite, NULL, NULL, clif_parse_GuildReplyInvite, NULL, NULL, clif_parse_GuildChangeNotice, NULL,
- // 170
- clif_parse_GuildRequestAlliance, NULL, clif_parse_GuildReplyAlliance, NULL, NULL, NULL, NULL, NULL,
- clif_parse_ItemIdentify, NULL, clif_parse_UseCard, NULL, clif_parse_InsertCard, NULL, clif_parse_GuildMessage, NULL,
-
- // 180
- clif_parse_GuildOpposition, NULL, NULL, clif_parse_GuildDelAlliance, NULL, NULL, NULL, NULL,
- NULL, NULL, clif_parse_QuitGame, NULL, NULL, NULL, clif_parse_ProduceMix, NULL,
- // 190
- clif_parse_UseSkillToPos, NULL, NULL, clif_parse_SolveCharName, NULL, NULL, NULL, clif_parse_ResetChar,
- NULL, NULL, NULL, NULL, clif_parse_LGMmessage, clif_parse_GMHide, NULL, clif_parse_CatchPet,
- // 1a0
- NULL, clif_parse_PetMenu, NULL, NULL, NULL, clif_parse_ChangePetName, NULL, clif_parse_SelectEgg,
- NULL, clif_parse_SendEmotion, NULL, NULL, NULL, NULL, clif_parse_SelectArrow, clif_parse_ChangeCart,
- // 1b0
- NULL, NULL, clif_parse_OpenVending, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, clif_parse_Shift, clif_parse_Shift, clif_parse_Recall, clif_parse_Recall, NULL, NULL,
-
- // 1c0
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, clif_parse_AutoSpell,
- NULL,
- // 1d0
- NULL, NULL, NULL, NULL, NULL, clif_parse_NpcStringInput, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, clif_parse_GMReqNoChatCount,
- // 1e0
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, clif_parse_sn_doridori,
- clif_parse_CreateParty2, NULL, NULL, NULL, NULL, clif_parse_sn_explosionspirits, NULL, NULL,
- // 1f0
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
- // 200
- NULL, NULL, clif_parse_friends_list_add, clif_parse_friends_list_remove, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- // 210
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-#if 0
- case 0xd3: clif_parse_IgnoreList
-#endif
- },
- {NULL},
- {NULL},
- {NULL},
- {NULL},
- {NULL},
- {NULL}
-};
-
-/*==========================================
- * クライアントからのパケット解析
- * socket.cのdo_parsepacketから呼び出される
- *------------------------------------------
- */
-static int clif_parse(int fd) {
- int packet_len = 0, cmd, packet_ver;
- struct map_session_data *sd;
-
- sd = session[fd]->session_data;
-
- // 接続が切れてるので後始末
- if (!chrif_isconnect() || session[fd]->eof) { // char鯖に繋がってない間は接続禁止 (!chrif_isconnect())
- if (sd && sd->state.auth) {
- if (chrif_isconnect())
- clif_quitsave(fd, sd);
- if (sd->status.name != NULL)
- printf("Player [%s] has logged off your server.\n", sd->status.name); // Player logout display [Valaris]
- else
- printf("Player with account [%d] has logged off your server.\n", sd->bl.id); // Player logout display [Yor]
- } 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;
-
- //printf("clif_parse: connection #%d, packet: 0x%x (with being read: %d bytes).\n", fd, RFIFOW(fd,0), RFIFOREST(fd));
-
- 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;
- }
-
- // get packet version before to parse
- packet_ver = 0;
- if (sd)
- packet_ver = sd->packet_ver;
- // check authentification packet to know packet version
- else {
- // 0x72
- if (cmd == 0x72) {
- if (RFIFOREST(fd) >= 39 && (RFIFOB(fd,38) == 0 || RFIFOB(fd,38) == 1)) // 00 = Female, 01 = Male
- packet_ver = 7; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- else if (RFIFOREST(fd) >= 22 && (RFIFOB(fd,21) == 0 || RFIFOB(fd,21) == 1)) // 00 = Female, 01 = Male
- packet_ver = 6; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- else if (RFIFOREST(fd) >= 19 && (RFIFOB(fd,18) == 0 || RFIFOB(fd,18) == 1)) // 00 = Female, 01 = Male
- packet_ver = 5; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- // else probably incomplete packet
- else if (RFIFOREST(fd) < 19)
- return 0;
- // 0x7E
- } else if (cmd == 0x7E) {
- if (RFIFOREST(fd) >= 37 && (RFIFOB(fd,36) == 0 || RFIFOB(fd,36) == 1)) // 00 = Female, 01 = Male
- packet_ver = 9; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- else if (RFIFOREST(fd) >= 33 && (RFIFOB(fd,32) == 0 || RFIFOB(fd,32) == 1)) // 00 = Female, 01 = Male
- packet_ver = 8; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- // else probably incomplete packet
- else if (RFIFOREST(fd) < 33)
- return 0;
- // 0xF5
- } else {
- if (RFIFOREST(fd) >= 34 && (RFIFOB(fd,33) == 0 || RFIFOB(fd,33) == 1)) // 00 = Female, 01 = Male
- packet_ver = 10; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- else if (RFIFOREST(fd) >= 33 && (RFIFOB(fd,32) == 0 || RFIFOB(fd,32) == 1)) // 00 = Female, 01 = Male
- packet_ver = 12; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- else if (RFIFOREST(fd) >= 32 && (RFIFOB(fd,31) == 0 || RFIFOB(fd,31) == 1)) // 00 = Female, 01 = Male
- packet_ver = 11; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- else if (RFIFOREST(fd) >= 29 && (RFIFOB(fd,28) == 0 || RFIFOB(fd,28) == 1)) // 00 = Female, 01 = Male
- packet_ver = 13; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor])
- // else probably incomplete packet
- else if (RFIFOREST(fd) < 29)
- return 0;
- }
- // check if version is accepted
- if ((packet_ver == 5 && (battle_config.packet_ver_flag & 1) == 0) ||
- (packet_ver == 6 && (battle_config.packet_ver_flag & 2) == 0) ||
- (packet_ver == 7 && (battle_config.packet_ver_flag & 4) == 0) ||
- (packet_ver == 8 && (battle_config.packet_ver_flag & 8) == 0) ||
- (packet_ver == 9 && (battle_config.packet_ver_flag & 16) == 0) ||
- (packet_ver == 10 && (battle_config.packet_ver_flag & 32) == 0) ||
- (packet_ver == 11 && (battle_config.packet_ver_flag & 64) == 0) ||
- (packet_ver == 12 && (battle_config.packet_ver_flag & 128) == 0) ||
- (packet_ver == 13 && (battle_config.packet_ver_flag & 256) == 0)) {
- WFIFOW(fd,0) = 0x6a;
- WFIFOB(fd,2) = 5; // 05 = Game's EXE is not the latest version
- WFIFOSET(fd,23);
- session[fd]->eof = 1;
- return 0;
- }
- }
-
- // ゲーム用以外パケットか、認証を終える前に0072以外が来たら、切断する
- if (packet_ver < 5 || packet_ver > 13 || // if packet is not inside these values: session is incorrect?? or auth packet is unknown
- cmd >= 0x220 || packet_size_table[packet_ver-5][cmd] == 0) {
- if (!fd)
- return 0;
- session[fd]->eof = 1;
- printf("clif_parse: session #%d, packet 0x%x (%d bytes received) -> disconnected.\n", fd, cmd, RFIFOREST(fd));
- return 0;
- }
-
- // パケット長を計算
- packet_len = packet_size_table[packet_ver-5][cmd];
- if (packet_len == -1) {
- if (RFIFOREST(fd) < 4)
- return 0; // 可変長パケットで長さの所までデータが来てない
- packet_len = RFIFOW(fd,2);
- if (packet_len < 4 || packet_len > 32768) {
- 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_ver < 8 && clif_parse_func_table[0][cmd]) { // packet version 5-6-7 use same functions, but size are different
- // パケット処理
- clif_parse_func_table[0][cmd](fd, sd);
- } else if (packet_ver >= 8 && clif_parse_func_table[packet_ver - 7][cmd]) {
- // パケット処理
- clif_parse_func_table[packet_ver - 7][cmd](fd, sd);
- } 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;
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-int do_init_clif(void) {
-#ifndef __WIN32
- int i;
-#endif
-
- // functions of packet version 5-6-7 are same, but size are different
- // init packet function calls for packet ver 8
- memcpy(clif_parse_func_table[1], clif_parse_func_table[0], sizeof(clif_parse_func_table[0]));
- clif_parse_func_table[1][0x072] = clif_parse_DropItem;
- clif_parse_func_table[1][0x07e] = clif_parse_WantToConnection;
- clif_parse_func_table[1][0x085] = clif_parse_UseSkillToId;
- clif_parse_func_table[1][0x089] = clif_parse_GetCharNameRequest;
- clif_parse_func_table[1][0x08c] = clif_parse_UseSkillToPos;
- clif_parse_func_table[1][0x094] = clif_parse_TakeItem;
- clif_parse_func_table[1][0x09b] = clif_parse_WalkToXY;
- clif_parse_func_table[1][0x09f] = clif_parse_ChangeDir;
- clif_parse_func_table[1][0x0a2] = clif_parse_UseSkillToPos;
- clif_parse_func_table[1][0x0a7] = clif_parse_SolveCharName;
- clif_parse_func_table[1][0x0f3] = clif_parse_GlobalMessage;
- clif_parse_func_table[1][0x0f5] = clif_parse_UseItem;
- clif_parse_func_table[1][0x0f7] = clif_parse_TickSend;
- clif_parse_func_table[1][0x113] = clif_parse_MoveToKafra;
- clif_parse_func_table[1][0x116] = clif_parse_CloseKafra;
- clif_parse_func_table[1][0x190] = clif_parse_MoveFromKafra;
- clif_parse_func_table[1][0x193] = clif_parse_ActionRequest;
- // init packet function calls for packet ver 9 (same function of packet version 8, but size are different)
- memcpy(clif_parse_func_table[2], clif_parse_func_table[1], sizeof(clif_parse_func_table[0]));
- // init packet function calls for packet ver 10
- memcpy(clif_parse_func_table[3], clif_parse_func_table[2], sizeof(clif_parse_func_table[0]));
- clif_parse_func_table[3][0x072] = clif_parse_UseItem;
- clif_parse_func_table[3][0x07e] = clif_parse_MoveToKafra;
- clif_parse_func_table[3][0x085] = clif_parse_ActionRequest;
- clif_parse_func_table[3][0x089] = clif_parse_WalkToXY;
- clif_parse_func_table[3][0x08c] = clif_parse_UseSkillToPos;
- clif_parse_func_table[3][0x094] = clif_parse_DropItem;
- clif_parse_func_table[3][0x09b] = clif_parse_GetCharNameRequest;
- clif_parse_func_table[3][0x09f] = clif_parse_GlobalMessage;
- clif_parse_func_table[3][0x0a2] = clif_parse_SolveCharName;
- clif_parse_func_table[3][0x0a7] = clif_parse_UseSkillToPos;
- clif_parse_func_table[3][0x0f3] = clif_parse_ChangeDir;
- clif_parse_func_table[3][0x0f5] = clif_parse_WantToConnection;
- clif_parse_func_table[3][0x0f7] = clif_parse_CloseKafra;
- clif_parse_func_table[3][0x113] = clif_parse_TakeItem;
- clif_parse_func_table[3][0x116] = clif_parse_TickSend;
- clif_parse_func_table[3][0x190] = clif_parse_UseSkillToId;
- clif_parse_func_table[3][0x193] = clif_parse_MoveFromKafra;
- // init packet function calls for packet ver 11 (same function of packet version 10, but size are different)
- memcpy(clif_parse_func_table[4], clif_parse_func_table[3], sizeof(clif_parse_func_table[0]));
- // init packet function calls for packet ver 12 (same function of packet version 11, but size are different)
- memcpy(clif_parse_func_table[5], clif_parse_func_table[4], sizeof(clif_parse_func_table[0]));
- // init packet function calls for packet ver 13 (same function of packet version 12, but size are different)
- memcpy(clif_parse_func_table[6], clif_parse_func_table[5], sizeof(clif_parse_func_table[0]));
-
- // size of packet version 5
- memcpy(&packet_size_table[0], &packet_len_table, sizeof(packet_len_table));
- // size of packet version 6
- memcpy(&packet_size_table[1], &packet_size_table[0], sizeof(packet_len_table));
- packet_size_table[1][0x072] = 22;
- packet_size_table[1][0x085] = 8;
- packet_size_table[1][0x0a7] = 13;
- packet_size_table[1][0x113] = 15;
- packet_size_table[1][0x116] = 15;
- packet_size_table[1][0x190] = 95;
- // size of packet version 7
- memcpy(&packet_size_table[2], &packet_size_table[1], sizeof(packet_len_table));
- packet_size_table[2][0x072] = 39;
- packet_size_table[2][0x085] = 9;
- packet_size_table[2][0x09b] = 13;
- packet_size_table[2][0x09f] = 10;
- packet_size_table[2][0x0a7] = 17;
- packet_size_table[2][0x113] = 19;
- packet_size_table[2][0x116] = 19;
- packet_size_table[2][0x190] = 99;
- // size of packet version 8
- memcpy(&packet_size_table[3], &packet_size_table[2], sizeof(packet_len_table));
- packet_size_table[3][0x072] = 14;
- packet_size_table[3][0x07e] = 33;
- packet_size_table[3][0x085] = 20;
- packet_size_table[3][0x089] = 15;
- packet_size_table[3][0x08c] = 23;
- packet_size_table[3][0x094] = 10;
- packet_size_table[3][0x09b] = 6;
- packet_size_table[3][0x09f] = 13;
- packet_size_table[3][0x0a2] = 103;
- packet_size_table[3][0x0a7] = 12;
- packet_size_table[3][0x0f3] = -1;
- packet_size_table[3][0x0f5] = 17;
- packet_size_table[3][0x0f7] = 10;
- packet_size_table[3][0x113] = 16;
- packet_size_table[3][0x116] = 2;
- packet_size_table[3][0x190] = 26;
- packet_size_table[3][0x193] = 9;
- // size of packet version 9
- memcpy(&packet_size_table[4], &packet_size_table[3], sizeof(packet_len_table));
- packet_size_table[4][0x072] = 17;
- packet_size_table[4][0x07e] = 37;
- packet_size_table[4][0x085] = 26;
- packet_size_table[4][0x089] = 12;
- packet_size_table[4][0x08c] = 40;
- packet_size_table[4][0x094] = 13;
- packet_size_table[4][0x09b] = 15;
- packet_size_table[4][0x09f] = 12;
- packet_size_table[4][0x0a2] = 120;
- packet_size_table[4][0x0a7] = 11;
-// packet_size_table[4][0x0f3] = -1;
- packet_size_table[4][0x0f5] = 24;
- packet_size_table[4][0x0f7] = 13;
- packet_size_table[4][0x113] = 23;
-// packet_size_table[4][0x116] = 2;
- packet_size_table[4][0x190] = 26;
- packet_size_table[4][0x193] = 18;
- // new packet
- packet_size_table[4][0x20f] = 10;
- packet_size_table[4][0x210] = 22;
- packet_size_table[4][0x212] = 26;
- packet_size_table[4][0x213] = 26;
- packet_size_table[4][0x214] = 42;
- // size of packet version 10
- memcpy(&packet_size_table[5], &packet_size_table[4], sizeof(packet_len_table));
- packet_size_table[5][0x072] = 20;
- packet_size_table[5][0x07e] = 19;
- packet_size_table[5][0x085] = 23;
- packet_size_table[5][0x089] = 9;
- packet_size_table[5][0x08c] = 105;
- packet_size_table[5][0x094] = 17;
- packet_size_table[5][0x09b] = 14;
- packet_size_table[5][0x09f] = -1;
- packet_size_table[5][0x0a2] = 14;
- packet_size_table[5][0x0a7] = 25;
- packet_size_table[5][0x0f3] = 10;
- packet_size_table[5][0x0f5] = 34;
- packet_size_table[5][0x0f7] = 2;
- packet_size_table[5][0x113] = 11;
- packet_size_table[5][0x116] = 11;
- packet_size_table[5][0x190] = 22;
- packet_size_table[5][0x193] = 17;
- // size of packet version 11
- memcpy(&packet_size_table[6], &packet_size_table[5], sizeof(packet_len_table));
- packet_size_table[6][0x072] = 18;
- packet_size_table[6][0x07e] = 25;
- packet_size_table[6][0x085] = 9;
- packet_size_table[6][0x089] = 14;
- packet_size_table[6][0x08c] = 109;
- packet_size_table[6][0x094] = 19;
- packet_size_table[6][0x09b] = 10;
-// packet_size_table[6][0x09f] = -1;
- packet_size_table[6][0x0a2] = 10;
- packet_size_table[6][0x0a7] = 29;
- packet_size_table[6][0x0f3] = 18;
- packet_size_table[6][0x0f5] = 32;
-// packet_size_table[6][0x0f7] = 2;
- packet_size_table[6][0x113] = 14;
- packet_size_table[6][0x116] = 14;
- packet_size_table[6][0x190] = 14;
- packet_size_table[6][0x193] = 12;
- // size of packet version 12
- memcpy(&packet_size_table[7], &packet_size_table[6], sizeof(packet_len_table));
- packet_size_table[7][0x072] = 17;
- packet_size_table[7][0x07e] = 16;
-// packet_size_table[7][0x085] = 9;
- packet_size_table[7][0x089] = 6;
- packet_size_table[7][0x08c] = 103;
- packet_size_table[7][0x094] = 14;
- packet_size_table[7][0x09b] = 15;
-// packet_size_table[7][0x09f] = -1;
- packet_size_table[7][0x0a2] = 12;
- packet_size_table[7][0x0a7] = 23;
- packet_size_table[7][0x0f3] = 13;
- packet_size_table[7][0x0f5] = 33;
-// packet_size_table[7][0x0f7] = 2;
- packet_size_table[7][0x113] = 10;
- packet_size_table[7][0x116] = 10;
- packet_size_table[7][0x190] = 20;
- packet_size_table[7][0x193] = 26;
- // size of packet version 13
- memcpy(&packet_size_table[8], &packet_size_table[7], sizeof(packet_len_table));
- packet_size_table[8][0x072] = 13;
- packet_size_table[8][0x07e] = 13;
- packet_size_table[8][0x085] = 15;
-// packet_size_table[8][0x089] = 6;
- packet_size_table[8][0x08c] = 108;
- packet_size_table[8][0x094] = 12;
- packet_size_table[8][0x09b] = 10;
-// packet_size_table[8][0x09f] = -1;
- packet_size_table[8][0x0a2] = 16;
- packet_size_table[8][0x0a7] = 28;
- packet_size_table[8][0x0f3] = 15;
- packet_size_table[8][0x0f5] = 29;
-// packet_size_table[8][0x0f7] = 2;
- packet_size_table[8][0x113] = 9;
- packet_size_table[8][0x116] = 9;
- packet_size_table[8][0x190] = 26;
- packet_size_table[8][0x193] = 22;
-
- set_defaultparse(clif_parse);
-#ifdef __WIN32
- if (!make_listen_port(map_port)) {
- printf("cant bind game port\n");
- exit(1);
- }
-#else
- for(i = 0; i < 10; i++) {
- if (make_listen_port(map_port))
- break;
- sleep(20);
- }
- if (i == 10) {
- printf("cant bind game port\n");
- exit(1);
- }
-#endif
-
- add_timer_func_list(clif_waitclose, "clif_waitclose");
- add_timer_func_list(clif_clearchar_delay_sub, "clif_clearchar_delay_sub");
-
- return 0;
-}
-
+// $Id: clif.c 2200 2004-11-07 11:49:58Z Yor $ + +#define DUMP_UNKNOWN_PACKET 1 + +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdarg.h> +#ifdef __WIN32 +#define __USE_W32_SOCKETS +#include <windows.h> +#else +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#endif +#include <time.h> + +#include "../common/socket.h" +#include "../common/timer.h" +#include "../common/malloc.h" +#include "../common/version.h" +#include "../common/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" + +#ifdef MEMWATCH +#include "memwatch.h" +#endif + +#define STATE_BLIND 0x10 + +static const int packet_len_table[0x220] = { + 10, 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, 0, 0, +//#0x0040 + 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, 55, 17, 3, 37, 46, -1, 23, -1, 3,108, 3, 2, +#if PACKETVER < 2 + 3, 28, 19, 11, 3, -1, 9, 5, 52, 51, 56, 58, 41, 2, 6, 6, +#else // 78-7b 亀島以降 lv99エフェクト用 + 3, 28, 19, 11, 3, -1, 9, 5, 54, 53, 58, 60, 41, 2, 6, 6, +#endif +//#0x0080 + 7, 3, 2, 2, 2, 5, 16, 12, 10, 7, 29, 23, -1, -1, -1, 0, // 0x8b unknown... size 2 or 23? + 7, 22, 28, 2, 6, 30, -1, -1, 3, -1, -1, 5, 9, 17, 17, 6, + 23, 6, 6, -1, -1, -1, -1, 8, 7, 6, 7, 4, 7, 0, -1, 6, + 8, 8, 3, 3, -1, 6, 6, -1, 7, 6, 2, 5, 6, 44, 5, 3, +//#0x00C0 + 7, 2, 6, 8, 6, 7, -1, -1, -1, -1, 3, 3, 6, 6, 2, 27, + 3, 4, 4, 2, -1, -1, 3, -1, 6, 14, 3, -1, 28, 29, -1, -1, + 30, 30, 26, 2, 6, 26, 3, 3, 8, 19, 5, 2, 3, 2, 2, 2, + 3, 2, 6, 8, 21, 8, 8, 2, 2, 26, 3, -1, 6, 27, 30, 10, + +//#0x0100 + 2, 6, 6, 30, 79, 31, 10, 10, -1, -1, 4, 6, 6, 2, 11, -1, + 10, 39, 4, 10, 31, 35, 10, 18, 2, 13, 15, 20, 68, 2, 3, 16, + 6, 14, -1, -1, 21, 8, 8, 8, 8, 8, 2, 2, 3, 4, 2, -1, + 6, 86, 6, -1, -1, 7, -1, 6, 3, 16, 4, 4, 4, 6, 24, 26, +//#0x0140 + 22, 14, 6, 10, 23, 19, 6, 39, 8, 9, 6, 27, -1, 2, 6, 6, + 110, 6, -1, -1, -1, -1, -1, 6, -1, 54, 66, 54, 90, 42, 6, 42, + -1, -1, -1, -1, -1, 30, -1, 3, 14, 3, 30, 10, 43, 14,186,182, + 14, 30, 10, 3, -1, 6,106, -1, 4, 5, 4, -1, 6, 7, -1, -1, +//#0x0180 + 6, 3,106, 10, 10, 34, 0, 6, 8, 4, 4, 4, 29, -1, 10, 6, +#if PACKETVER < 1 + 90, 86, 24, 6, 30,102, 8, 4, 8, 4, 14, 10, -1, 6, 2, 6, +#else // 196 comodo以降 状態表示アイコン用 + 90, 86, 24, 6, 30,102, 9, 4, 8, 4, 14, 10, -1, 6, 2, 6, +#endif + 3, 3, 35, 5, 11, 26, -1, 4, 4, 6, 10, 12, 6, -1, 4, 4, + 11, 7, -1, 67, 12, 18,114, 6, 3, 6, 26, 26, 26, 26, 2, 3, +//#0x01C0, Set 0x1d5=-1 + 2, 14, 10, -1, 22, 22, 4, 2, 13, 97, 0, 9, 9, 30, 6, 28, + 8, 14, 10, 35, 6, -1, 4, 11, 54, 53, 60, 2, -1, 47, 33, 6, + 30, 8, 34, 14, 2, 6, 26, 2, 28, 81, 6, 10, 26, 2, -1, -1, + -1, -1, 20, 10, 32, 9, 34, 14, 2, 6, 48, 56, -1, 4, 5, 10, +//#0x200 + 26, -1, 26, 10, 18, 26, 11, 34, 14, 36, 10, 19, 0, -1, 24, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +// size list for each packet version after packet version 4. +static int packet_size_table[9][0x220]; + +// 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]; + +/*========================================== + * 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 { + if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version + 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) { + if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version + 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) { + if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version + 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; + if (packet_size_table[cd->usersd[i]->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version + if (cd->usersd[i]->fd >=0 && session[cd->usersd[i]->fd]) // Added check to see if session exists [PoW] + 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; + if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version + 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) { + if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version + memcpy(WFIFOP(sd->fd,0), buf, len); + WFIFOSET(sd->fd,len); + } + } + } + } + } + break; + case SELF: + sd = (struct map_session_data *)bl; + if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version + 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; + if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version + 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) { + if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version + 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; + if (packet_size_table[sd->packet_ver-5][RBUFW(buf,0)]) { // packet must exist for the client version + 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_len_table[0x73]); + + 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_len_table[0x81]); + + 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_len_table[0xb3]); + + 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_len_table[0x9e]; +} + +/*========================================== + * + *------------------------------------------ + */ +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_len_table[0x9e], &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_len_table[0xa1], &fitem->bl, AREA); + } else { + memcpy(WFIFOP(fd,0), buf, 6); + WFIFOSET(fd,packet_len_table[0xa1]); + } + + 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_len_table[0x80], bl, AREA); + } else { + WBUFB(buf,6) = type; + clif_send(buf, packet_len_table[0x80], 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; + + tmpbl = (struct block_list*)aCalloc(1, sizeof(struct block_list)); + + 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_len_table[0x80]); + + return 0; +} + +/*========================================== + * + *------------------------------------------ + */ +static int clif_set0078(struct map_session_data *sd, unsigned char *buf) { + int level; + + 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_len_table[0x78]; + } + +#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_len_table[0x78]; +#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_len_table[0x1d8]; +#endif +} + +/*========================================== + * + *------------------------------------------ + */ +static int clif_set007b(struct map_session_data *sd,unsigned char *buf) { + int level; + + 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_len_table[0x7b]; + } + +#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_len_table[0x7b]; +#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_len_table[0x1da]; +#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_len_table[0x1b0],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_len_table[0x1b0],&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_len_table[0x1a4]); + + WBUFW(buf,0)=0x1a4; + WBUFB(buf,2)=3; + WBUFL(buf,3)=md->bl.id; + WBUFL(buf,7)=nameid; + + clif_send(buf,packet_len_table[0x1a4],&md->bl,AREA); + + return 0; +} + +/*========================================== + * MOB表示1 + *------------------------------------------ + */ +static int clif_mob0078(struct mob_data *md, unsigned char *buf) +{ + int level; + + memset(buf,0,packet_len_table[0x78]); + + 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 && md->guild_id) { // 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,22)=g->emblem_id; + WBUFL(buf,26)=gc->guild_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_len_table[0x78]; +} + +/*========================================== + * MOB表示2 + *------------------------------------------ + */ +static int clif_mob007b(struct mob_data *md, unsigned char *buf) { + int level; + + memset(buf,0,packet_len_table[0x7b]); + + 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 && md->guild_id) { // 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_len_table[0x7b]; +} + +/*========================================== + * + *------------------------------------------ + */ +static int clif_npc0078(struct npc_data *nd, unsigned char *buf) { + struct guild *g; + + nullpo_retr(0, nd); + + memset(buf,0,packet_len_table[0x78]); + + 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_len_table[0x78]; +} + +// 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_len_table[0x7b]); + + 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_len_table[0x7b]; +} + +/*========================================== + * + *------------------------------------------ + */ +static int clif_pet0078(struct pet_data *pd, unsigned char *buf) { + int view,level; + + nullpo_retr(0, pd); + + memset(buf,0,packet_len_table[0x78]); + + 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_len_table[0x78]; +} + +/*========================================== + * + *------------------------------------------ + */ +static int clif_pet007b(struct pet_data *pd, unsigned char *buf) { + int view,level; + + nullpo_retr(0, pd); + + memset(buf,0,packet_len_table[0x7b]); + + 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_len_table[0x7b]; +} + +/*========================================== + * + *------------------------------------------ + */ +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_len_table[0x1e1]; +} + +/*========================================== + * + *------------------------------------------ + */ +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_len_table[0x192]); + + 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_len_table[0x119]); + + 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_len_table[0x119], &sd->bl, SELF); + + memset(buf, 0, packet_len_table[0x7c]); + + 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_len_table[0x7c], &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_len_table[0x79], &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_len_table[0x1d9], &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_len_table[0x7c]); + + 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_len_table[0x7c],&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_len_table[0x7c]); + + 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_len_table[0x7c],&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_len_table[0x7c]); + + 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_len_table[0x7c],&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_len_table[0x7f]); + + 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_len_table[0x87]); + + 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) { + struct map_session_data *sd; + + // if player is not already in the game (double connection probably) + if ((sd = session[fd]->session_data) == NULL) { + // limited timer, just to send information. + add_timer(gettick() + 1000, clif_waitclose, fd, 0); + } else + 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_len_table[0x91]); + + 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_len_table[0x92]); + + 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_len_table[0x88], 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_len_table[0xc4]); + + 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_len_table[0xb5]); + + 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_len_table[0xb6]); + + 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_len_table[0x142]); + + 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_len_table[0x1d4]); + + 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_len_table[0x144]); + + 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_len_table[0x1b3]); + + 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_len_table[0xa0]); + 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_len_table[0xaf]); + + 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_len_table[0x1ab],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_len_table[0xc3],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_len_table[0x1d7],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_len_table[0x1d7],bl,AREA); + } else { + WBUFW(buf,0)=0xc3; + WBUFL(buf,2)=bl->id; + WBUFB(buf,6)=type; + WBUFB(buf,7)=val; + clif_send(buf,packet_len_table[0xc3],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_len_table[0xbd]); + + 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_len_table[0x013c]); + + 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_len_table[0x013b]); + + 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_len_table[0xbc]); + + 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_len_table[0xaa]); + + 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_len_table[0xac]); + + 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_len_table[0x19b],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_len_table[0x1f3]); + + WBUFW(buf,0) = 0x1f3; + WBUFL(buf,2) = bl->id; + WBUFL(buf,6) = type; + + clif_send(buf, packet_len_table[0x1f3], 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_len_table[0x119],bl,AREA_WOS); + clif_spawnpc(sd); + } else + clif_send(buf,packet_len_table[0x119],bl,AREA); + } else + clif_send(buf,packet_len_table[0x119],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_len_table[0xa8]); + } + 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_len_table[0xa8]); +#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_len_table[0x1c8],&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_len_table[0xd6]); + + 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_len_table[0xd8]); + WFIFOSET(fd,packet_len_table[0xd8]); + } else { + clif_send(buf,packet_len_table[0xd8],*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_len_table[0xda]); + + 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_len_table[0xdc],&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_len_table[0xe1]*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_len_table[0xdd],&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_len_table[0xe5]); + + 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_len_table[0xe7]); + + 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_len_table[0xe9]); + + 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_len_table[0xea]); + + 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_len_table[0xec]); + + 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_len_table[0xee]); + + 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_len_table[0xf0]); + + 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_len_table[0xf2]); + + 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_len_table[0xf4]); + + 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_len_table[0xf2]); + + 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_len_table[0xf4]); + + 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_len_table[0xf6]); + + 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_len_table[0xf8]); + + 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_len_table[0x1e1]); + } + 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_len_table[0x8a],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_len_table[0x9d]); +} +/*========================================== + * 場所スキルエフェクトが視界に入る + *------------------------------------------ + */ +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_len_table[0x11f]); + 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_len_table[0x11f]); +#else + memset(WFIFOP(fd,0),0,packet_len_table[0x1c9]); + WFIFOW(fd, 0)=0x1c9; + WFIFOL(fd, 2)=unit->bl.id; + WFIFOL(fd, 6)=unit->group->src_id; + WFIFOW(fd,10)=unit->bl.x; + WFIFOW(fd,12)=unit->bl.y; + WFIFOB(fd,14)=unit->group->unit_id; + WFIFOB(fd,15)=1; + 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_len_table[0x1c9]); +#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_len_table[0x120]); + 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_len_table[0x1ac],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_len_table[0x147]); + + 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_len_table[0x10e]); + + 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_len_table[0x13e], 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_len_table[0x1b9], 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_len_table[0x110]); + + 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_len_table[0x114],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_len_table[0x1de],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_len_table[0x115],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_len_table[0x11a],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_len_table[0x117],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_len_table[0x11f]); + 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_len_table[0x11f],&unit->bl,AREA); +#else + memset(WBUFP(buf, 0),0,packet_len_table[0x1c9]); + 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_len_table[0x1c9],&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_len_table[0x120],&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_len_table[0x11c]); + 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_len_table[0x11e]); + 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_len_table[0x189]); + 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_len_table[0x18c],&sd->bl,PARTY_AREA); + else{ + memcpy(WFIFOP(sd->fd,0),buf,packet_len_table[0x18c]); + WFIFOSET(sd->fd,packet_len_table[0x18c]); + } + 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_len_table[0x196],bl,AREA); + return 0; +} + +/*========================================== + * Send message (modified by [Yor]) + *------------------------------------------ + */ +int clif_displaymessage(const int fd, char* mes) +{ + //Console [Wizputer] + if (fd == 0) + printf("\033[0;36mConsole: \033[0m\033[1m%s\033[0m\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 *buf; + int lp; + + lp = (flag & 0x10) ? 8 : 4; + buf = (unsigned char*)aCalloc(len + lp, sizeof(unsigned char)); + + 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) 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_len_table[0x13d]); + + 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_len_table[0x148],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_len_table[0x199]); + + 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_len_table[0x19a]); + } 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_len_table[0x19a],&sd->bl,AREA); + else + clif_send(buf,packet_len_table[0x19a],&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_len_table[0x199],&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_len_table[0x188]); + + 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_len_table[0x98]); + 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_len_table[0x194]); + }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_len_table[0x17d]); + 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_len_table[0x179]); + 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_len_table[0x147]); + 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_len_table[0x124]); + 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_len_table[0x125]); + + 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_len_table[0x12d]); + + 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_len_table[0x131]); + WFIFOSET(fd,packet_len_table[0x131]); + }else{ + clif_send(buf,packet_len_table[0x131],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_len_table[0x132]); + WFIFOSET(fd,packet_len_table[0x132]); + }else{ + clif_send(buf,packet_len_table[0x132],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_len_table[0x135]); + + 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_len_table[0x137]); + + 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_len_table[0xfa]); + 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_len_table[0xfe]); + 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_len_table[0xfd]); + 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_len_table[0x101],&sd->bl,PARTY); + else { + memcpy(WFIFOP(sd->fd,0),buf,packet_len_table[0x101]); + WFIFOSET(sd->fd,packet_len_table[0x101]); + } + 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_len_table[0x105],&sd->bl,PARTY); + } else if (sd!=NULL) { + memcpy(WFIFOP(sd->fd,0),buf,packet_len_table[0x105]); + WFIFOSET(sd->fd,packet_len_table[0x105]); + } + 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_len_table[0x107],&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_len_table[0x106],&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_len_table[0x104],&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_len_table[0x139]); + 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_len_table[0x18f]); + 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_len_table[0x19e]); + + 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_len_table[0x1a0]); + + 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_len_table[0x1a4]); + + 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_len_table[0x1a2]); + + 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_len_table[0x1aa]); + + 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_len_table[0x1aa],&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_len_table[0x1a4]); + + WBUFW(buf,0)=0x1a4; + WBUFB(buf,2)=4; + WBUFL(buf,3)=bl->id; + WBUFL(buf,7)=param; + + clif_send(buf,packet_len_table[0x1a4],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_len_table[0x1a4]); + + 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_len_table[0x1a4],&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_len_table[0x1a3]); + + 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_len_table[0x1cd]); + 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_len_table[0x1cf],&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_len_table[0x1d0],&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_len_table[0x1d2],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_len_table[0x1d1],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_len_table[0x192],&bl,AREA); + else + clif_send(buf,packet_len_table[0x192],&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_len_table[0x10c],&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_len_table[0x10a]); + 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_len_table[0x10b]); + 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_len_table[0x167]); + 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_len_table[0x16c]); + 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_len_table[0x16c]); + 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_len_table[0x16d],&sd->bl,GUILD); + }else + clif_send(buf,packet_len_table[0x16d],&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_len_table[0x14e]); + 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_len_table[WFIFOW(fd,0)]); + 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_len_table[0x16f]); + 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_len_table[0x16a]); + 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_len_table[0x169]); + 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_len_table[0x15a],&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_len_table[0x15c],&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 *buf; + + buf = (unsigned char*)aCalloc(len + 4, sizeof(unsigned char)); + + 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) 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_len_table[0x171]); + 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_len_table[0x173]); + 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_len_table[0x184]); + 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_len_table[0x181]); + 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_len_table[0x185],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_len_table[0x15e]); + 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_len_table[0xc0],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_len_table[0x191],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_len_table[0x1ea], 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_len_table[0x1e6]&sd->bl,AREA); + } + return; +} +*/ +/*========================================== + * 座る + *------------------------------------------ + */ +void clif_sitting(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_len_table[0x8a], &sd->bl, AREA); +} + +/*========================================== + * + *------------------------------------------ + */ +int clif_disp_onlyself(struct map_session_data *sd, char *mes, int len) +{ + unsigned char *buf; + + nullpo_retr(0, sd); + + buf = (unsigned char*)aCalloc(len + 8, sizeof(unsigned char)); + + 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) 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_len_table[0xcd]); + return 0; +} + +void clif_parse_QuitGame(int fd,struct map_session_data *sd); + +int clif_GM_kick(struct map_session_data *sd,struct map_session_data *tsd,int type) +{ + nullpo_retr(0, tsd); + + if(type) + clif_GM_kickack(sd,tsd->status.account_id); + tsd->opt1 = tsd->opt2 = 0; + WFIFOW(tsd->fd,0) = 0x18b; + WFIFOW(tsd->fd,2) = 0; + WFIFOSET(tsd->fd,packet_len_table[0x18b]); + clif_setwaitclose(tsd->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_len_table[0xd1]); + + 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_len_table[0xd2]); + + 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_len_table[0x1d3]); + + 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_len_table[0x1f3]); + + WBUFW(buf,0) = 0x1f3; + WBUFL(buf,2) = bl->id; + WBUFL(buf,6) = type; + + if (flag == 2) { + struct map_session_data *sd; + 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_len_table[0x1f3], bl, SELF); + else if (!flag) + clif_send(buf, packet_len_table[0x1f3], bl, AREA); + + return 0; + +} +// ------------ +// clif_parse_* +// ------------ +// パケット読み取って色々操作 +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_WantToConnection(int fd, struct map_session_data *sd) +{ + struct map_session_data *old_sd; + int account_id; // account_id in the packet 0x72 or 0x7E + + if (sd) { + if (battle_config.error_log) + printf("clif_parse_WantToConnection : invalid request?\n"); + return; + } + + // 0x72 + if (RFIFOW(fd,0) == 0x72) { + //printf("Received bytes %d with packet 0x72.\n", RFIFOREST(fd)); + if (RFIFOREST(fd) >= 39 && (RFIFOB(fd,38) == 0 || RFIFOB(fd,38) == 1)) // 00 = Female, 01 = Male + account_id = RFIFOL(fd,12); + else if (RFIFOREST(fd) >= 22 && (RFIFOB(fd,21) == 0 || RFIFOB(fd,21) == 1)) // 00 = Female, 01 = Male + account_id = RFIFOL(fd,5); + else // old packet version + account_id = RFIFOL(fd,2); + // 0x7E + } else if (RFIFOW(fd,0) == 0x7E) { + //printf("Received bytes %d with packet 0x7E.\n", RFIFOREST(fd)); + if (RFIFOREST(fd) >= 37 && (RFIFOB(fd,36) == 0 || RFIFOB(fd,36) == 1)) // 00 = Female, 01 = Male + account_id = RFIFOL(fd,9); + else + account_id = RFIFOL(fd,12); + // 0xF5 + } else { + //printf("Received bytes %d with packet 0xF5.\n", RFIFOREST(fd)); + if (RFIFOREST(fd) >= 34 && (RFIFOB(fd,33) == 0 || RFIFOB(fd,33) == 1)) // 00 = Female, 01 = Male + account_id = RFIFOL(fd,7); + else if (RFIFOREST(fd) >= 33 && (RFIFOB(fd,32) == 0 || RFIFOB(fd,32) == 1)) // 00 = Female, 01 = Male + account_id = RFIFOL(fd,12); + else if (RFIFOREST(fd) >= 32 && (RFIFOB(fd,31) == 0 || RFIFOB(fd,31) == 1)) // 00 = Female, 01 = Male + account_id = RFIFOL(fd,10); + else // 29 28 28 + account_id = RFIFOL(fd,5); + } + + // if same account already connected, we disconnect the 2 sessions + if ((old_sd = map_id2sd(account_id)) != NULL) { + clif_authfail_fd(fd, 2); // same id + clif_authfail_fd(old_sd->fd, 2); // same id + } else { + sd = session[fd]->session_data = (struct map_session_data*)aCalloc(1, sizeof(struct map_session_data)); + sd->fd = fd; + + // 0x72 + if (RFIFOW(fd,0) == 0x72) { + if (RFIFOREST(fd) >= 39 && (RFIFOB(fd,38) == 0 || RFIFOB(fd,38) == 1)) { // 00 = Female, 01 = Male + sd->packet_ver = 7; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + pc_setnewpc(sd, account_id, RFIFOL(fd,22), RFIFOL(fd,30), RFIFOL(fd,34), RFIFOB(fd,38), fd); + } else if (RFIFOREST(fd) >= 22 && (RFIFOB(fd,21) == 0 || RFIFOB(fd,21) == 1)) { // 00 = Female, 01 = Male + sd->packet_ver = 6; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + pc_setnewpc(sd, account_id, RFIFOL(fd,9), RFIFOL(fd,13), RFIFOL(fd,17), RFIFOB(fd,21), fd); + } else { // old packet version + sd->packet_ver = 5; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + pc_setnewpc(sd, account_id, RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOB(fd,18), fd); + } + // 0x7E + } else if (RFIFOW(fd,0) == 0x7E) { + if (RFIFOREST(fd) >= 37 && (RFIFOB(fd,36) == 0 || RFIFOB(fd,36) == 1)) { // 00 = Female, 01 = Male + sd->packet_ver = 9; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + pc_setnewpc(sd, account_id, RFIFOL(fd,21), RFIFOL(fd,28), RFIFOL(fd,32), RFIFOB(fd,36), fd); + } else { + sd->packet_ver = 8; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + pc_setnewpc(sd, account_id, RFIFOL(fd,18), RFIFOL(fd,24), RFIFOL(fd,28), RFIFOB(fd,32), fd); + } + // 0xF5 + } else { + if (RFIFOREST(fd) >= 34 && (RFIFOB(fd,33) == 0 || RFIFOB(fd,33) == 1)) { // 00 = Female, 01 = Male + sd->packet_ver = 10; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + pc_setnewpc(sd, account_id, RFIFOL(fd,15), RFIFOL(fd,25), RFIFOL(fd,29), RFIFOB(fd,33), fd); + } else if (RFIFOREST(fd) >= 33 && (RFIFOB(fd,32) == 0 || RFIFOB(fd,32) == 1)) { // 00 = Female, 01 = Male + sd->packet_ver = 12; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + pc_setnewpc(sd, account_id, RFIFOL(fd,18), RFIFOL(fd,24), RFIFOL(fd,28), RFIFOB(fd,32), fd); + } else if (RFIFOREST(fd) >= 32 && (RFIFOB(fd,31) == 0 || RFIFOB(fd,31) == 1)) { // 00 = Female, 01 = Male + sd->packet_ver = 11; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + pc_setnewpc(sd, account_id, RFIFOL(fd,17), RFIFOL(fd,23), RFIFOL(fd,27), RFIFOB(fd,31), fd); + } else { // 29 + sd->packet_ver = 13; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + pc_setnewpc(sd, account_id, RFIFOL(fd,14), RFIFOL(fd,20), RFIFOL(fd,24), RFIFOB(fd,28), fd); + } + } + + WFIFOL(fd,0) = sd->bl.id; + WFIFOSET(fd,4); + + map_addiddb(&sd->bl); + + chrif_authreq(sd); + } + + return; +} + +/*========================================== + * 007d クライアント側マップ読み込み完了 + * map侵入時に必要なデータを全て送りつける + *------------------------------------------ + */ +void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) +{ +// 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) { + nullpo_retv(sd); + + switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + case 8: + sd->client_tick = RFIFOL(fd,6); + break; + case 9: + sd->client_tick = RFIFOL(fd,9); + break; + case 10: + sd->client_tick = RFIFOL(fd,7); + break; + case 11: + sd->client_tick = RFIFOL(fd,10); + break; + case 12: + sd->client_tick = RFIFOL(fd,6); + break; + case 13: + sd->client_tick = RFIFOL(fd,5); + break; + default: // old version by default (and version 6 + 7) + sd->client_tick = RFIFOL(fd,2); + break; + } + sd->server_tick = gettick(); + clif_servertick(sd); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_WalkToXY(int fd, struct map_session_data *sd) { + 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); + + switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + case 6: + x = RFIFOB(fd,5) * 4 + (RFIFOB(fd,6) >> 6); + y = ((RFIFOB(fd,6) & 0x3f) << 4) + (RFIFOB(fd,7) >> 4); + break; + case 7: + x = RFIFOB(fd,6) * 4 + (RFIFOB(fd,7) >> 6); + y = ((RFIFOB(fd,7) & 0x3f) << 4) + (RFIFOB(fd,8) >> 4); + break; + case 8: + x = RFIFOB(fd,3) * 4 + (RFIFOB(fd,4) >> 6); + y = ((RFIFOB(fd,4) & 0x3f) << 4) + (RFIFOB(fd,5) >> 4); + break; + case 9: + x = RFIFOB(fd,12) * 4 + (RFIFOB(fd,13) >> 6); + y = ((RFIFOB(fd,13) & 0x3f) << 4) + (RFIFOB(fd,14) >> 4); + break; + case 10: + x = RFIFOB(fd,6) * 4 + (RFIFOB(fd,7) >> 6); + y = ((RFIFOB(fd,7) & 0x3f) << 4) + (RFIFOB(fd,8) >> 4); + break; + case 11: + x = RFIFOB(fd,11) * 4 + (RFIFOB(fd,12) >> 6); + y = ((RFIFOB(fd,12) & 0x3f) << 4) + (RFIFOB(fd,13) >> 4); + break; + case 12: + x = RFIFOB(fd,3) * 4 + (RFIFOB(fd,4) >> 6); + y = ((RFIFOB(fd,4) & 0x3f) << 4) + (RFIFOB(fd,5) >> 4); + break; + case 13: + x = RFIFOB(fd,3) * 4 + (RFIFOB(fd,4) >> 6); + y = ((RFIFOB(fd,4) & 0x3f) << 4) + (RFIFOB(fd,5) >> 4); + break; + default: // old version by default + x = RFIFOB(fd,2) * 4 + (RFIFOB(fd,3) >> 6); + y = ((RFIFOB(fd,3) & 0x3f) << 4) + (RFIFOB(fd,4) >> 4); + break; + } + pc_walktoxy(sd, x, y); + +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_QuitGame(int fd, struct map_session_data *sd) { + 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_len_table[0x18b]); + 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_len_table[0x18b]); + +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd) { + struct block_list *bl; + int account_id; + + switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + case 8: + account_id = RFIFOL(fd,11); + break; + case 9: + account_id = RFIFOL(fd,8); + break; + case 10: + account_id = RFIFOL(fd,10); + break; + case 11: + account_id = RFIFOL(fd,6); + break; + case 12: + account_id = RFIFOL(fd,11); + break; + case 13: + account_id = RFIFOL(fd,6); + break; + default: // old version by default (+ packet version 6 and 7) + account_id = RFIFOL(fd,2); + break; + } + 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_len_table[0x195]); + break; + } + } + WFIFOSET(fd,packet_len_table[0x95]); + } + break; + case BL_PET: + memcpy(WFIFOP(fd,6), ((struct pet_data*)bl)->name, 24); + WFIFOSET(fd,packet_len_table[0x95]); + break; + case BL_NPC: + memcpy(WFIFOP(fd,6), ((struct npc_data*)bl)->name, 24); + WFIFOSET(fd,packet_len_table[0x95]); + 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 && md->guild_id) { + 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_len_table[0x195]); + } else { + WFIFOSET(fd,packet_len_table[0x95]); + } + } 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_len_table[0x195]); + } else { + WFIFOSET(fd,packet_len_table[0x95]); + } + } + 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) { // S 008c <len>.w <str>.?B + char *message; + char *buf; + + nullpo_retv(sd); + + if ((is_atcommand(fd, sd, RFIFOP(fd,4), 0) != AtCommand_None) || + (sd->sc_data && + (sd->sc_data[SC_BERSERK].timer != -1 || //バーサーク時は会話も不可 + sd->sc_data[SC_NOCHAT].timer != -1 ))) //チャット禁止 + return; + + message = (char*)aCalloc(RFIFOW(fd,2) + 128, sizeof(char)); + buf = (char*)aCalloc(RFIFOW(fd,2) + 4, sizeof(char)); + + //printf("clif_parse_GlobalMessage: message: '%s'.\n", RFIFOP(fd,4)); + if (strncmp(RFIFOP(fd,4), 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,4)) == 0) + strcpy(message, " This player sends a void name and a void message."); + else + sprintf(message, " This player sends (name:message): '%s'.", RFIFOP(fd,4)); + 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,2)); + WFIFOW(fd,0) = 0x8e; + WFIFOSET(fd, WFIFOW(fd,2)); + + if(message) free(message); + if(buf) 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) { +// /m /mapmove (as @rura GM command) + char output[100]; + char map_name[17]; + + nullpo_retv(sd); + + memset(output, '\0', sizeof(output)); + memset(map_name, '\0', sizeof(map_name)); + + if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) && + (pc_isGM(sd) >= get_atcommand_level(AtCommand_MapMove))) { + memcpy(map_name, RFIFOP(fd,2), 16); + sprintf(output, "%s %d %d", map_name, RFIFOW(fd,18), RFIFOW(fd,20)); + atcommand_rura(fd, sd, "@rura", output); + } + + return; +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_ChangeDir(int fd, struct map_session_data *sd) { + unsigned char buf[64]; + short headdir, dir; + + nullpo_retv(sd); + + switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + case 7: + headdir = RFIFOW(fd,5); + dir = RFIFOB(fd,12); + break; + case 8: + headdir = RFIFOW(fd,5); + dir = RFIFOB(fd,12); + break; + case 9: + headdir = RFIFOW(fd,7); + dir = RFIFOB(fd,11); + break; + case 10: + headdir = RFIFOW(fd,4); + dir = RFIFOB(fd,9); + break; + case 11: + headdir = RFIFOW(fd,8); + dir = RFIFOB(fd,17); + break; + case 12: + headdir = RFIFOW(fd,5); + dir = RFIFOB(fd,12); + break; + case 13: + headdir = RFIFOW(fd,6); + dir = RFIFOB(fd,14); + break; + default: // old version by default (and packet version 6) + headdir = RFIFOW(fd,2); + dir = RFIFOB(fd,4); + break; + } + + pc_setdir(sd, dir, headdir); + + WBUFW(buf,0) = 0x9c; + WBUFL(buf,2) = sd->bl.id; + WBUFW(buf,6) = headdir; + WBUFB(buf,8) = dir; + if (sd->disguise > 23 && sd->disguise < 4001) // mob disguises [Valaris] + clif_send(buf, packet_len_table[0x9c], &sd->bl, AREA); + else + clif_send(buf, packet_len_table[0x9c], &sd->bl, AREA_WOS); + +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_Emotion(int fd, struct map_session_data *sd) { + unsigned char buf[64]; + + nullpo_retv(sd); + + if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, NV_BASIC) >= 2) { + WBUFW(buf,0) = 0xc0; + WBUFL(buf,2) = sd->bl.id; + WBUFB(buf,6) = RFIFOB(fd,2); + clif_send(buf, packet_len_table[0xc0], &sd->bl, AREA); + } else + clif_skill_fail(sd, 1, 0, 1); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_HowManyConnections(int fd, struct map_session_data *sd) { + WFIFOW(fd,0) = 0xc2; + WFIFOL(fd,2) = map_getusers(); + WFIFOSET(fd,packet_len_table[0xc2]); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_ActionRequest(int fd, struct map_session_data *sd) { + 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); + + switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + case 8: + target_id = RFIFOL(fd,3); + action_type = RFIFOB(fd,8); + break; + case 9: + target_id = RFIFOL(fd,7); + action_type = RFIFOB(fd,17); + break; + case 10: + target_id = RFIFOL(fd,9); + action_type = RFIFOB(fd,22); + break; + case 11: + target_id = RFIFOL(fd,3); + action_type = RFIFOB(fd,8); + break; + case 12: + target_id = RFIFOL(fd,3); + action_type = RFIFOB(fd,8); + break; + case 13: + target_id = RFIFOL(fd,4); + action_type = RFIFOB(fd,14); + break; + default: // old version by default (and packet version 6 and 7) + target_id = RFIFOL(fd,2); + action_type = RFIFOB(fd,6); + break; + } + + 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(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_len_table[0x8a], &sd->bl, AREA); + break; + } +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_Restart(int fd, struct map_session_data *sd) { + nullpo_retv(sd); + + switch(RFIFOB(fd,2)) { + 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_len_table[0x018b]); + } + break; + } +} + +/*========================================== + * Transmission of a wisp (S 0096 <len>.w <nick>.24B <message>.?B) + *------------------------------------------ + */ +void clif_parse_Wis(int fd, struct map_session_data *sd) { // S 0096 <len>.w <nick>.24B <message>.?B // rewritten by [Yor] + char *gm_command; + struct map_session_data *dstsd; + int i; + + //printf("clif_parse_Wis: message: '%s'.\n", RFIFOP(fd,28)); + + gm_command = (char*)aCalloc(strlen(RFIFOP(fd,28)) + 28, sizeof(char)); // 24+3+(RFIFOW(fd,2)-28)+1 or 24+3+(strlen(RFIFOP(fd,28))+1 (size can be wrong with hacker) + + sprintf(gm_command, "%s : %s", sd->status.name, RFIFOP(fd,28)); + if ((is_atcommand(fd, sd, gm_command, 0) != AtCommand_None) || + (sd && sd->sc_data && + (sd->sc_data[SC_BERSERK].timer!=-1 || //バーサーク時は会話も不可 + sd->sc_data[SC_NOCHAT].timer != -1))) //チャット禁止 + { + if(gm_command) free(gm_command); + return; + } + + if(gm_command) free(gm_command); + + // searching destination character + dstsd = map_nick2sd(RFIFOP(fd,4)); + // player is not on this map-server + if (dstsd == NULL || + // At this point, don't send wisp/page if it's not exactly the same name, because (example) + // if there are 'Test' player on an other map-server and 'test' player on this map-server, + // and if we ask for 'Test', we must not contact 'test' player + // so, we send information to inter-server, which is the only one which decide (and copy correct name). + strcmp(dstsd->status.name, RFIFOP(fd,4)) != 0) // not exactly same name + // send message to inter-server + intif_wis_message(sd, RFIFOP(fd,4), RFIFOP(fd,28), RFIFOW(fd,2)-28); + // player is on this map-server + else { + // if you send to your self, don't send anything to others + if (dstsd->fd == fd) // but, normaly, it's impossible! + clif_wis_message(fd, wisp_server_name, "You can not page yourself. Sorry.", strlen("You can not page yourself. Sorry.") + 1); + // otherwise, send message and answer immediatly + else { + if (dstsd->ignoreAll == 1) + clif_wis_end(fd, 2); // type: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + else { + // if player ignore the source character + for(i = 0; i < MAX_IGNORE_LIST; i++) + if (strcmp(dstsd->ignore[i].name, sd->status.name) == 0) { + clif_wis_end(fd, 2); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + break; + } + // if source player not found in ignore list + if (i == MAX_IGNORE_LIST) { + clif_wis_message(dstsd->fd, sd->status.name, RFIFOP(fd,28), RFIFOW(fd,2) - 28); + clif_wis_end(fd, 0); // type: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + } + } + } + } + + return; +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_GMmessage(int fd, struct map_session_data *sd) { +// /b + nullpo_retv(sd); + + if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) && + (pc_isGM(sd) >= get_atcommand_level(AtCommand_Broadcast))) + intif_GMmessage(RFIFOP(fd,4), RFIFOW(fd,2)-4, 0); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_TakeItem(int fd, struct map_session_data *sd) { + struct flooritem_data *fitem; + int map_object_id; + + nullpo_retv(sd); + + switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + case 7: + map_object_id = RFIFOL(fd,6); + break; + case 8: + map_object_id = RFIFOL(fd,6); + break; + case 9: + map_object_id = RFIFOL(fd,9); + break; + case 10: + map_object_id = RFIFOL(fd,7); + break; + case 11: + map_object_id = RFIFOL(fd,10); + break; + case 12: + map_object_id = RFIFOL(fd,6); + break; + case 13: + map_object_id = RFIFOL(fd,5); + break; + default: // old version by default (and packet version 6) + map_object_id = RFIFOL(fd,2); + break; + } + 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 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; + + switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + case 8: + item_index = RFIFOW(fd,5) - 2; + item_amount = RFIFOW(fd,12); + break; + case 9: + item_index = RFIFOW(fd,8) - 2; + item_amount = RFIFOW(fd,15); + break; + case 10: + item_index = RFIFOW(fd,6) - 2; + item_amount = RFIFOW(fd,15); + break; + case 11: + item_index = RFIFOW(fd,12) - 2; + item_amount = RFIFOW(fd,17); + break; + case 12: + item_index = RFIFOW(fd,5) - 2; + item_amount = RFIFOW(fd,12); + break; + case 13: + item_index = RFIFOW(fd,6) - 2; + item_amount = RFIFOW(fd,10); + break; + default: // old version by default (+ packet version 6 and 7) + item_index = RFIFOW(fd,2) - 2; + item_amount = RFIFOW(fd,4); + break; + } + + pc_dropitem(sd, item_index, item_amount); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_UseItem(int fd, struct map_session_data *sd) { + 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); + + switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + case 6: + pc_useitem(sd,RFIFOW(fd,5)-2); + break; + case 7: + pc_useitem(sd,RFIFOW(fd,6)-2); + break; + case 8: + pc_useitem(sd,RFIFOW(fd,6)-2); + break; + case 9: + pc_useitem(sd,RFIFOW(fd,9)-2); + break; + case 10: + pc_useitem(sd,RFIFOW(fd,7)-2); + break; + case 11: + pc_useitem(sd,RFIFOW(fd,10)-2); + break; + case 12: + pc_useitem(sd,RFIFOW(fd,6)-2); + break; + case 13: + pc_useitem(sd,RFIFOW(fd,5)-2); + break; + default: // old version by default + pc_useitem(sd,RFIFOW(fd,2)-2); + break; + } +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_EquipItem(int fd,struct map_session_data *sd) +{ + int index; + + nullpo_retv(sd); + + if(pc_isdead(sd)) { + clif_clearchar_area(&sd->bl,1); + return; + } + index = RFIFOW(fd,2)-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,4)=0x8000; // 矢を無理やり装備できるように(−−; + pc_equipitem(sd,index,RFIFOW(fd,4)); + } else + pet_equipitem(sd,index); + } +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_UnequipItem(int fd,struct map_session_data *sd) +{ + int index; + + nullpo_retv(sd); + + if(pc_isdead(sd)) { + clif_clearchar_area(&sd->bl,1); + return; + } + index = RFIFOW(fd,2)-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,index,0); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_NpcClicked(int fd,struct map_session_data *sd) +{ + 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,2)); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_NpcBuySellSelected(int fd,struct map_session_data *sd) +{ + npc_buysellsel(sd,RFIFOL(fd,2),RFIFOB(fd,6)); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_NpcBuyListSend(int fd,struct map_session_data *sd) +{ + int fail=0,n; + unsigned short *item_list; + + n = (RFIFOW(fd,2)-4) /4; + item_list = (unsigned short*)RFIFOP(fd,4); + + fail = npc_buylist(sd,n,item_list); + + WFIFOW(fd,0)=0xca; + WFIFOB(fd,2)=fail; + WFIFOSET(fd,packet_len_table[0xca]); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_NpcSellListSend(int fd,struct map_session_data *sd) +{ + int fail=0,n; + unsigned short *item_list; + + n = (RFIFOW(fd,2)-4) /4; + item_list = (unsigned short*)RFIFOP(fd,4); + + fail = npc_selllist(sd,n,item_list); + + WFIFOW(fd,0)=0xcb; + WFIFOB(fd,2)=fail; + WFIFOSET(fd,packet_len_table[0xcb]); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_CreateChatRoom(int fd,struct map_session_data *sd) +{ + if(battle_config.basic_skill_check == 0 || pc_checkskill(sd,NV_BASIC) >= 4){ + chat_createchat(sd,RFIFOW(fd,4),RFIFOB(fd,6),RFIFOP(fd,7),RFIFOP(fd,15),RFIFOW(fd,2)-15); + } else + clif_skill_fail(sd,1,0,3); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_ChatAddMember(int fd,struct map_session_data *sd) +{ + chat_joinchat(sd,RFIFOL(fd,2),RFIFOP(fd,6)); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_ChatRoomStatusChange(int fd,struct map_session_data *sd) +{ + chat_changechatstatus(sd,RFIFOW(fd,4),RFIFOB(fd,6),RFIFOP(fd,7),RFIFOP(fd,15),RFIFOW(fd,2)-15); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_ChangeChatOwner(int fd,struct map_session_data *sd) +{ + chat_changechatowner(sd,RFIFOP(fd,6)); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_KickFromChat(int fd,struct map_session_data *sd) +{ + chat_kickchat(sd,RFIFOP(fd,2)); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_ChatLeave(int fd,struct map_session_data *sd) +{ + chat_leavechat(sd); +} + +/*========================================== + * 取引要請を相手に送る + *------------------------------------------ + */ +void clif_parse_TradeRequest(int fd,struct map_session_data *sd) +{ + nullpo_retv(sd); + + if(battle_config.basic_skill_check == 0 || pc_checkskill(sd,NV_BASIC) >= 1){ + trade_traderequest(sd,RFIFOL(sd->fd,2)); + } else + clif_skill_fail(sd,1,0,0); +} + +/*========================================== + * 取引要請 + *------------------------------------------ + */ +void clif_parse_TradeAck(int fd,struct map_session_data *sd) +{ + nullpo_retv(sd); + + trade_tradeack(sd,RFIFOB(sd->fd,2)); +} + +/*========================================== + * アイテム追加 + *------------------------------------------ + */ +void clif_parse_TradeAddItem(int fd,struct map_session_data *sd) +{ + nullpo_retv(sd); + + trade_tradeadditem(sd,RFIFOW(sd->fd,2),RFIFOL(sd->fd,4)); +} + +/*========================================== + * アイテム追加完了(ok押し) + *------------------------------------------ + */ +void clif_parse_TradeOk(int fd,struct map_session_data *sd) +{ + trade_tradeok(sd); +} + +/*========================================== + * 取引キャンセル + *------------------------------------------ + */ +void clif_parse_TradeCansel(int fd,struct map_session_data *sd) +{ + trade_tradecancel(sd); +} + +/*========================================== + * 取引許諾(trade押し) + *------------------------------------------ + */ +void clif_parse_TradeCommit(int fd,struct map_session_data *sd) +{ + trade_tradecommit(sd); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_StopAttack(int fd,struct map_session_data *sd) +{ + pc_stopattack(sd); +} + +/*========================================== + * カートへアイテムを移す + *------------------------------------------ + */ +void clif_parse_PutItemToCart(int fd,struct map_session_data *sd) +{ + nullpo_retv(sd); + + if(sd->npc_id!=0 || sd->vender_id != 0) + return; + pc_putitemtocart(sd,RFIFOW(fd,2)-2,RFIFOL(fd,4)); +} +/*========================================== + * カートからアイテムを出す + *------------------------------------------ + */ +void clif_parse_GetItemFromCart(int fd,struct map_session_data *sd) +{ + nullpo_retv(sd); + + if(sd->npc_id!=0 || sd->vender_id != 0) return; + pc_getitemfromcart(sd,RFIFOW(fd,2)-2,RFIFOL(fd,4)); +} + +/*========================================== + * 付属品(鷹,ペコ,カート)をはずす + *------------------------------------------ + */ +void clif_parse_RemoveOption(int fd,struct map_session_data *sd) +{ + 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) +{ + pc_setcart(sd,RFIFOW(fd,2)); +} + +/*========================================== + * ステータスアップ + *------------------------------------------ + */ +void clif_parse_StatusUp(int fd,struct map_session_data *sd) +{ + pc_statusup(sd,RFIFOW(fd,2)); +} + +/*========================================== + * スキルレベルアップ + *------------------------------------------ + */ +void clif_parse_SkillUp(int fd,struct map_session_data *sd) +{ + pc_skillup(sd,RFIFOW(fd,2)); +} + +/*========================================== + * スキル使用(ID指定) + *------------------------------------------ + */ +void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) { + 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; + + switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + case 6: + skilllv = RFIFOW(fd,4); + skillnum = RFIFOW(fd,9); + target_id = RFIFOL(fd,11); + break; + case 7: + skilllv = RFIFOW(fd,7); + skillnum = RFIFOW(fd,9); + target_id = RFIFOL(fd,15); + break; + case 8: + skilllv = RFIFOW(fd,7); + skillnum = RFIFOW(fd,12); + target_id = RFIFOL(fd,16); + break; + case 9: + skilllv = RFIFOW(fd,11); + skillnum = RFIFOW(fd,18); + target_id = RFIFOL(fd,22); + break; + case 10: + skilllv = RFIFOW(fd,9); + skillnum = RFIFOW(fd,15); + target_id = RFIFOL(fd,18); + break; + case 11: + skilllv = RFIFOW(fd,4); + skillnum = RFIFOW(fd,7); + target_id = RFIFOL(fd,10); + break; + case 12: + skilllv = RFIFOW(fd,7); + skillnum = RFIFOW(fd,12); + target_id = RFIFOL(fd,16); + break; + case 13: + skilllv = RFIFOW(fd,4); + skillnum = RFIFOW(fd,10); + target_id = RFIFOL(fd,22); + break; + default: // old version by default + skilllv = RFIFOW(fd,2); + skillnum = RFIFOW(fd,4); + target_id = RFIFOL(fd,6); + break; + } + + 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 skillnum, skilllv, lv, x, y; + unsigned int tick = gettick(); + int skillmoreinfo; + + nullpo_retv(sd); + + if (sd->npc_id != 0 || sd->vender_id != 0) return; + if(sd->chatID) return; + + skillmoreinfo = -1; + switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + case 6: + skilllv = RFIFOW(fd,4); + skillnum = RFIFOW(fd,9); + x = RFIFOW(fd,11); + y = RFIFOW(fd,13); + if (RFIFOW(fd,0) == 0x190) + skillmoreinfo = 15; + break; + case 7: + skilllv = RFIFOW(fd,7); + skillnum = RFIFOW(fd,9); + x = RFIFOW(fd,15); + y = RFIFOW(fd,17); + if (RFIFOW(fd,0) == 0x190) + skillmoreinfo = 19; + break; + case 8: + skilllv = RFIFOW(fd,3); + skillnum = RFIFOW(fd,6); + x = RFIFOW(fd,17); + y = RFIFOW(fd,21); + if (RFIFOW(fd,0) == 0x0a2) + skillmoreinfo = 23; + break; + case 9: + skilllv = RFIFOW(fd,5); + skillnum = RFIFOW(fd,15); + x = RFIFOW(fd,29); + y = RFIFOW(fd,38); + if (RFIFOW(fd,0) == 0x0a2) + skillmoreinfo = 40; + break; + case 10: + skilllv = RFIFOW(fd,10); + skillnum = RFIFOW(fd,14); + x = RFIFOW(fd,18); + y = RFIFOW(fd,23); + if (RFIFOW(fd,0) == 0x08c) + skillmoreinfo = 25; + break; + case 11: + skilllv = RFIFOW(fd,6); // 16? to check. + skillnum = RFIFOW(fd,20); + x = RFIFOW(fd,23); + y = RFIFOW(fd,27); + if (RFIFOW(fd,0) == 0x08c) + skillmoreinfo = 29; + break; + case 12: + skilllv = RFIFOW(fd,3); // 2? to check. + skillnum = RFIFOW(fd,6); + x = RFIFOW(fd,17); + y = RFIFOW(fd,21); + if (RFIFOW(fd,0) == 0x08c) + skillmoreinfo = 23; + break; + case 13: + skilllv = RFIFOW(fd,6); + skillnum = RFIFOW(fd,9); + x = RFIFOW(fd,23); + y = RFIFOW(fd,26); + if (RFIFOW(fd,0) == 0x08c) + skillmoreinfo = 28; + break; + default: // old version by default + skilllv = RFIFOW(fd,2); + skillnum = RFIFOW(fd,4); + x = RFIFOW(fd,6); + y = RFIFOW(fd,8); + if (RFIFOW(fd,0) == 0x190) + skillmoreinfo = 10; + break; + } + + if (skillnotok(skillnum, sd)) + return; + + if (skillmoreinfo != -1) { + if (pc_issit(sd)) { + clif_skill_fail(sd, skillnum, 0, 0); + return; + } + memcpy(talkie_mes, RFIFOP(fd,skillmoreinfo), 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) +{ + 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,2),RFIFOP(fd,4)); +} +/*========================================== + * メモ要求 + *------------------------------------------ + */ +void clif_parse_RequestMemo(int fd,struct map_session_data *sd) +{ + pc_memo(sd,-1); +} +/*========================================== + * アイテム合成 + *------------------------------------------ + */ +void clif_parse_ProduceMix(int fd,struct map_session_data *sd) +{ + nullpo_retv(sd); + + sd->state.produce_flag = 0; + skill_produce_mix(sd,RFIFOW(fd,2),RFIFOW(fd,4),RFIFOW(fd,6),RFIFOW(fd,8)); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_NpcSelectMenu(int fd,struct map_session_data *sd) +{ + nullpo_retv(sd); + + sd->npc_menu=RFIFOB(fd,6); + npc_scriptcont(sd,RFIFOL(fd,2)); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_NpcNextClicked(int fd,struct map_session_data *sd) +{ + npc_scriptcont(sd,RFIFOL(fd,2)); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_NpcAmountInput(int fd,struct map_session_data *sd) +{ + 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,6); //fixed by Lupus. npc_amount is (int) but was RFIFOL changing it to (unsigned int) + +#undef RFIFOL_ + + npc_scriptcont(sd,RFIFOL(fd,2)); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_NpcStringInput(int fd,struct map_session_data *sd) +{ + nullpo_retv(sd); + + if(RFIFOW(fd,2)-7 >= sizeof(sd->npc_str)){ + printf("clif: input string too long !\n"); + memcpy(sd->npc_str,RFIFOP(fd,8),sizeof(sd->npc_str)); + sd->npc_str[sizeof(sd->npc_str)-1]=0; + } else + strcpy(sd->npc_str,RFIFOP(fd,8)); + npc_scriptcont(sd,RFIFOL(fd,4)); +} + +/*========================================== + * + *------------------------------------------ + */ +void clif_parse_NpcCloseClicked(int fd,struct map_session_data *sd) +{ + npc_scriptcont(sd,RFIFOL(fd,2)); +} + +/*========================================== + * アイテム鑑定 + *------------------------------------------ + */ +void clif_parse_ItemIdentify(int fd,struct map_session_data *sd) +{ + pc_item_identify(sd,RFIFOW(fd,2)-2); +} +/*========================================== + * 矢作成 + *------------------------------------------ + */ +void clif_parse_SelectArrow(int fd,struct map_session_data *sd) +{ + nullpo_retv(sd); + + sd->state.make_arrow_flag = 0; + skill_arrow_create(sd,RFIFOW(fd,2)); +} +/*========================================== + * オートスペル受信 + *------------------------------------------ + */ +void clif_parse_AutoSpell(int fd,struct map_session_data *sd) +{ + skill_autospell(sd,RFIFOW(fd,2)); +} +/*========================================== + * カード使用 + *------------------------------------------ + */ +void clif_parse_UseCard(int fd,struct map_session_data *sd) +{ + clif_use_card(sd,RFIFOW(fd,2)-2); +} +/*========================================== + * カード挿入装備選択 + *------------------------------------------ + */ +void clif_parse_InsertCard(int fd,struct map_session_data *sd) +{ + pc_insert_card(sd,RFIFOW(fd,2)-2,RFIFOW(fd,4)-2); +} + +/*========================================== + * 0193 キャラID名前引き + *------------------------------------------ + */ +void clif_parse_SolveCharName(int fd, struct map_session_data *sd) { + int char_id; + + switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + case 8: + char_id = RFIFOL(fd,8); + break; + case 9: + char_id = RFIFOL(fd,7); + break; + case 10: + char_id = RFIFOL(fd,10); + break; + case 11: + char_id = RFIFOL(fd,6); + break; + case 12: + char_id = RFIFOL(fd,8); + break; + case 13: + char_id = RFIFOL(fd,12); + break; + default: // old version by default (+ packet version 6 and 7) + char_id = RFIFOL(fd,2); + break; + } + clif_solved_charname(sd, char_id); +} + +/*========================================== + * 0197 /resetskill /resetstate + *------------------------------------------ + */ +void clif_parse_ResetChar(int fd, struct map_session_data *sd) { + nullpo_retv(sd); + + if (battle_config.atc_gmonly == 0 || pc_isGM(sd)) { + switch(RFIFOW(fd,2)){ + case 0: + if (pc_isGM(sd) >= get_atcommand_level(AtCommand_ResetState)) + pc_resetstate(sd); + break; + case 1: + if (pc_isGM(sd) >= get_atcommand_level(AtCommand_ResetState)) + pc_resetskill(sd); + break; + } + } +} + +/*========================================== + * 019c /lb等 + *------------------------------------------ + */ +void clif_parse_LGMmessage(int fd, struct map_session_data *sd) { + 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) = RFIFOW(fd,2); + memcpy(WBUFP(buf,4), RFIFOP(fd,4), RFIFOW(fd,2) - 4); + clif_send(buf, RFIFOW(fd,2), &sd->bl, ALL_SAMEMAP); + } +} + +/*========================================== + * カプラ倉庫へ入れる + *------------------------------------------ + */ +void clif_parse_MoveToKafra(int fd, struct map_session_data *sd) { + int item_index, item_amount; + + nullpo_retv(sd); + + if (sd->npc_id != 0 || sd->vender_id != 0) + return; + + switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + case 8: + item_index = RFIFOW(fd,5) - 2; + item_amount = RFIFOL(fd,12); + break; + case 9: + item_index = RFIFOW(fd,5) - 2; + item_amount = RFIFOL(fd,19); + break; + case 10: + item_index = RFIFOW(fd,3) - 2; + item_amount = RFIFOL(fd,15); + break; + case 11: + item_index = RFIFOW(fd,6) - 2; + item_amount = RFIFOL(fd,21); + break; + case 12: + item_index = RFIFOW(fd,5) - 2; + item_amount = RFIFOL(fd,12); + break; + case 13: + item_index = RFIFOW(fd,6) - 2; + item_amount = RFIFOL(fd,9); + break; + default: // old version by default (+ packet version 6 and 7) + item_index = RFIFOW(fd,2) - 2; + item_amount = RFIFOL(fd,4); + break; + } + + if (item_index < 0 || item_index >= MAX_INVENTORY) + return; + + 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 item_index, item_amount; + + nullpo_retv(sd); + + switch (sd->packet_ver) { // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + case 8: + item_index = RFIFOW(fd,10) - 1; + item_amount = RFIFOL(fd,22); + break; + case 9: + item_index = RFIFOW(fd,11) - 1; + item_amount = RFIFOL(fd,22); + break; + case 10: + item_index = RFIFOW(fd,3) - 1; + item_amount = RFIFOL(fd,13); + break; + case 11: + item_index = RFIFOW(fd,4) - 1; + item_amount = RFIFOL(fd,8); + break; + case 12: + item_index = RFIFOW(fd,10) - 1; + item_amount = RFIFOL(fd,22); + break; + case 13: + item_index = RFIFOW(fd,12) - 1; + item_amount = RFIFOL(fd,18); + break; + default: // old version by default (+ packet version 6 and 7) + item_index = RFIFOW(fd,2) - 1; + item_amount = RFIFOL(fd,4); + break; + } + + if (sd->npc_id != 0 || sd->vender_id != 0) + return; + + 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) { + 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,2) - 2, RFIFOL(fd,4)); + else + storage_storageaddfromcart(sd, RFIFOW(fd,2) - 2, RFIFOL(fd,4)); +} + +/*========================================== + * カプラ倉庫から出す + *------------------------------------------ + */ +void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd) { + nullpo_retv(sd); + + if (sd->npc_id != 0 || sd->vender_id != 0) + return; + if (sd->state.storage_flag) + storage_guild_storagegettocart(sd, RFIFOW(fd,2)-1, RFIFOL(fd,4)); + else + storage_storagegettocart(sd, RFIFOW(fd,2)-1, RFIFOL(fd,4)); +} + +/*========================================== + * カプラ倉庫を閉じる + *------------------------------------------ + */ +void clif_parse_CloseKafra(int fd, struct map_session_data *sd) { + 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) { + if (battle_config.basic_skill_check == 0 || pc_checkskill(sd,NV_BASIC) >= 7) { + party_create(sd,RFIFOP(fd,2)); + } else + clif_skill_fail(sd,1,0,4); +} + +/*========================================== + * パーティを作る + *------------------------------------------ + */ +void clif_parse_CreateParty2(int fd, struct map_session_data *sd) { + if (battle_config.basic_skill_check == 0 || pc_checkskill(sd,NV_BASIC) >= 7){ + party_create(sd, RFIFOP(fd,2)); + } else + clif_skill_fail(sd, 1, 0, 4); +} + +/*========================================== + * パーティに勧誘 + *------------------------------------------ + */ +void clif_parse_PartyInvite(int fd, struct map_session_data *sd) { + party_invite(sd, RFIFOL(fd,2)); +} + +/*========================================== + * パーティ勧誘返答 + *------------------------------------------ + */ +void clif_parse_ReplyPartyInvite(int fd,struct map_session_data *sd) { + if(battle_config.basic_skill_check == 0 || pc_checkskill(sd,NV_BASIC) >= 5){ + party_reply_invite(sd,RFIFOL(fd,2),RFIFOL(fd,6)); + } else { + party_reply_invite(sd,RFIFOL(fd,2),-1); + clif_skill_fail(sd,1,0,4); + } +} + +/*========================================== + * パーティ脱退要求 + *------------------------------------------ + */ +void clif_parse_LeaveParty(int fd, struct map_session_data *sd) { + party_leave(sd); +} + +/*========================================== + * パーティ除名要求 + *------------------------------------------ + */ +void clif_parse_RemovePartyMember(int fd, struct map_session_data *sd) { + party_removemember(sd,RFIFOL(fd,2),RFIFOP(fd,6)); +} + +/*========================================== + * パーティ設定変更要求 + *------------------------------------------ + */ +void clif_parse_PartyChangeOption(int fd, struct map_session_data *sd) { + party_changeoption(sd, RFIFOW(fd,2), RFIFOW(fd,4)); +} + +/*========================================== + * パーティメッセージ送信要求 + *------------------------------------------ + */ +void clif_parse_PartyMessage(int fd, struct map_session_data *sd) { + nullpo_retv(sd); + + if (is_atcommand(fd, sd, RFIFOP(fd,4), 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,4), RFIFOW(fd,2)-4); +} + +/*========================================== + * 露店閉鎖 + *------------------------------------------ + */ +void clif_parse_CloseVending(int fd, struct map_session_data *sd) { + vending_closevending(sd); +} + +/*========================================== + * 露店アイテムリスト要求 + *------------------------------------------ + */ +void clif_parse_VendingListReq(int fd, struct map_session_data *sd) { + nullpo_retv(sd); + + vending_vendinglistreq(sd,RFIFOL(fd,2)); + if(sd->npc_id) + npc_event_dequeue(sd); +} + +/*========================================== + * 露店アイテム購入 + *------------------------------------------ + */ +void clif_parse_PurchaseReq(int fd, struct map_session_data *sd) { + vending_purchasereq(sd, RFIFOW(fd,2), RFIFOL(fd,4), RFIFOP(fd,8)); +} + +/*========================================== + * 露店開設 + *------------------------------------------ + */ +void clif_parse_OpenVending(int fd,struct map_session_data *sd) { + vending_openvending(sd, RFIFOW(fd,2), RFIFOP(fd,4), RFIFOB(fd,84), RFIFOP(fd,85)); +} + +/*========================================== + * /monster /item rewriten by [Yor] + *------------------------------------------ + */ +void clif_parse_GM_Monster_Item(int fd, struct map_session_data *sd) { + char monster_item_name[25]; + + nullpo_retv(sd); + + memset(monster_item_name, '\0', sizeof(monster_item_name)); + + if (battle_config.atc_gmonly == 0 || pc_isGM(sd)) { + memcpy(monster_item_name, RFIFOP(fd,2), 24); + + if (mobdb_searchname(monster_item_name) != 0) { + if (pc_isGM(sd) >= get_atcommand_level(AtCommand_Monster)) + atcommand_spawn(fd, sd, "@spawn", monster_item_name); // as @spawn + } else if (itemdb_searchname(monster_item_name) != NULL) { + if (pc_isGM(sd) >= get_atcommand_level(AtCommand_Item)) + atcommand_item(fd, sd, "@item", monster_item_name); // as @item + } + + } +} + +/*========================================== + * ギルドを作る + *------------------------------------------ + */ +void clif_parse_CreateGuild(int fd,struct map_session_data *sd) { + guild_create(sd, RFIFOP(fd,6)); +} + +/*========================================== + * ギルドマスターかどうか確認 + *------------------------------------------ + */ +void clif_parse_GuildCheckMaster(int fd, struct map_session_data *sd) { + clif_guild_masterormember(sd); +} + +/*========================================== + * ギルド情報要求 + *------------------------------------------ + */ +void clif_parse_GuildReqeustInfo(int fd, struct map_session_data *sd) { + switch(RFIFOL(fd,2)){ + 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,2)); + break; + } +} + +/*========================================== + * ギルド役職変更 + *------------------------------------------ + */ +void clif_parse_GuildChangePositionInfo(int fd, struct map_session_data *sd) { + int i; + + for(i = 4; i < RFIFOW(fd,2); 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 i; + + nullpo_retv(sd); + + for(i=4;i<RFIFOW(fd,2);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) { + struct guild *g=guild_search(RFIFOL(fd,2)); + if(g!=NULL) + clif_guild_emblem(sd,g); +} + +/*========================================== + * ギルドエンブレム変更 + *------------------------------------------ + */ +void clif_parse_GuildChangeEmblem(int fd,struct map_session_data *sd) { + guild_change_emblem(sd,RFIFOW(fd,2)-4,RFIFOP(fd,4)); +} + +/*========================================== + * ギルド告知変更 + *------------------------------------------ + */ +void clif_parse_GuildChangeNotice(int fd,struct map_session_data *sd) { + guild_change_notice(sd,RFIFOL(fd,2),RFIFOP(fd,6),RFIFOP(fd,66)); +} + +/*========================================== + * ギルド勧誘 + *------------------------------------------ + */ +void clif_parse_GuildInvite(int fd,struct map_session_data *sd) { + guild_invite(sd,RFIFOL(fd,2)); +} + +/*========================================== + * ギルド勧誘返信 + *------------------------------------------ + */ +void clif_parse_GuildReplyInvite(int fd,struct map_session_data *sd) { + guild_reply_invite(sd,RFIFOL(fd,2),RFIFOB(fd,6)); +} + +/*========================================== + * ギルド脱退 + *------------------------------------------ + */ +void clif_parse_GuildLeave(int fd,struct map_session_data *sd) { + guild_leave(sd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOP(fd,14)); +} + +/*========================================== + * ギルド追放 + *------------------------------------------ + */ +void clif_parse_GuildExplusion(int fd,struct map_session_data *sd) { + guild_explusion(sd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOP(fd,14)); +} + +/*========================================== + * ギルド会話 + *------------------------------------------ + */ +void clif_parse_GuildMessage(int fd,struct map_session_data *sd) { + nullpo_retv(sd); + + if (is_atcommand(fd, sd, RFIFOP(fd, 4), 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,4), RFIFOW(fd,2)-4); +} + +/*========================================== + * ギルド同盟要求 + *------------------------------------------ + */ +void clif_parse_GuildRequestAlliance(int fd, struct map_session_data *sd) { + guild_reqalliance(sd,RFIFOL(fd,2)); +} + +/*========================================== + * ギルド同盟要求返信 + *------------------------------------------ + */ +void clif_parse_GuildReplyAlliance(int fd, struct map_session_data *sd) { + guild_reply_reqalliance(sd,RFIFOL(fd,2),RFIFOL(fd,6)); +} + +/*========================================== + * ギルド関係解消 + *------------------------------------------ + */ +void clif_parse_GuildDelAlliance(int fd, struct map_session_data *sd) { + guild_delalliance(sd,RFIFOL(fd,2),RFIFOL(fd,6)); +} + +/*========================================== + * ギルド敵対 + *------------------------------------------ + */ +void clif_parse_GuildOpposition(int fd, struct map_session_data *sd) { + guild_opposition(sd,RFIFOL(fd,2)); +} + +/*========================================== + * ギルド解散 + *------------------------------------------ + */ +void clif_parse_GuildBreak(int fd, struct map_session_data *sd) { + guild_break(sd,RFIFOP(fd,2)); +} + +// pet +void clif_parse_PetMenu(int fd, struct map_session_data *sd) { + pet_menu(sd,RFIFOB(fd,2)); +} + +void clif_parse_CatchPet(int fd, struct map_session_data *sd) { + pet_catch_process2(sd,RFIFOL(fd,2)); +} + +void clif_parse_SelectEgg(int fd, struct map_session_data *sd) { + pet_select_egg(sd,RFIFOW(fd,2)-2); +} + +void clif_parse_SendEmotion(int fd, struct map_session_data *sd) { + nullpo_retv(sd); + + if(sd->pd) + clif_pet_emotion(sd->pd,RFIFOL(fd,2)); +} + +void clif_parse_ChangePetName(int fd, struct map_session_data *sd) { + pet_change_name(sd,RFIFOP(fd,2)); +} + +// Kick (right click menu for GM "(name) force to quit") +void clif_parse_GMKick(int fd, struct map_session_data *sd) { + struct block_list *target; + int tid = RFIFOL(fd,2); + + 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); + } +} + +/*========================================== + * /shift + *------------------------------------------ + */ +void clif_parse_Shift(int fd, struct map_session_data *sd) { // Rewriten by [Yor] + char player_name[25]; + + nullpo_retv(sd); + + memset(player_name, '\0', sizeof(player_name)); + + if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) && + (pc_isGM(sd) >= get_atcommand_level(AtCommand_JumpTo))) { + memcpy(player_name, RFIFOP(fd,2), 24); + atcommand_jumpto(fd, sd, "@jumpto", player_name); // as @jumpto + } + + return; +} + +/*========================================== + * /recall + *------------------------------------------ + */ +void clif_parse_Recall(int fd, struct map_session_data *sd) { // Added by RoVeRT + char player_name[25]; + + nullpo_retv(sd); + + memset(player_name, '\0', sizeof(player_name)); + + if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) && + (pc_isGM(sd) >= get_atcommand_level(AtCommand_Recall))) { + memcpy(player_name, RFIFOP(fd,2), 24); + atcommand_recall(fd, sd, "@recall", player_name); // as @recall + } + + return; +} + +void clif_parse_GMHide(int fd, struct map_session_data *sd) { // Modified by [Yor] + nullpo_retv(sd); + + //printf("%2x %2x %2x\n", RFIFOW(fd,0), RFIFOW(fd,2), RFIFOW(fd,4)); // R 019d <Option_value>.2B <flag>.2B + if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) && + (pc_isGM(sd) >= get_atcommand_level(AtCommand_Hide))) { + if (sd->status.option & OPTION_HIDE) { // OPTION_HIDE = 0x40 + sd->status.option &= ~OPTION_HIDE; // OPTION_HIDE = 0x40 + clif_displaymessage(fd, "Invisible: Off."); + } else { + sd->status.option |= OPTION_HIDE; // OPTION_HIDE = 0x40 + clif_displaymessage(fd, "Invisible: On."); + } + clif_changeoption(&sd->bl); + } +} + +/*========================================== + * GMによるチャット禁止時間付与 + *------------------------------------------ + */ +void clif_parse_GMReqNoChat(int fd,struct map_session_data *sd) +{ + int tid = RFIFOL(fd,2); + int type = RFIFOB(fd,6); + int limit = RFIFOW(fd,7); + 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_len_table[0x14b]); + 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 tid = RFIFOL(fd,2); + + WFIFOW(fd,0) = 0x1e0; + WFIFOL(fd,2) = tid; + sprintf(WFIFOP(fd,6),"%d",tid); +// memcpy(WFIFOP(fd,6), "TESTNAME", 24); + WFIFOSET(fd, packet_len_table[0x1e0]); + + return; +} + +void clif_parse_PMIgnore(int fd, struct map_session_data *sd) { // Rewritten by [Yor] + char output[512]; + char *nick; // S 00cf <nick>.24B <type>.B: 00 (/ex nick) deny speech from nick, 01 (/in nick) allow speech from nick + int i, pos; + + memset(output, '\0', sizeof(output)); + + nick = RFIFOP(fd,2); // speed up + RFIFOB(fd,25) = '\0'; // to be sure that the player name have at maximum 23 characters + //printf("Ignore: char '%s' state: %d\n", nick, RFIFOB(fd,26)); + + WFIFOW(fd,0) = 0x0d1; // R 00d1 <type>.B <fail>.B: type: 0: deny, 1: allow, fail: 0: success, 1: fail + WFIFOB(fd,2) = RFIFOB(fd,26); + // do nothing only if nick can not exist + if (strlen(nick) < 4) { + WFIFOB(fd,3) = 1; // fail + WFIFOSET(fd, packet_len_table[0x0d1]); + if (RFIFOB(fd,26) == 0) // type + clif_wis_message(fd, wisp_server_name, "It's impossible to block this player.", strlen("It's impossible to block this player.") + 1); + else + clif_wis_message(fd, wisp_server_name, "It's impossible to unblock this player.", strlen("It's impossible to unblock this player.") + 1); + return; + // name can exist + } else { + // deny action (we add nick only if it's not already exist + if (RFIFOB(fd,26) == 0) { // type + pos = -1; + for(i = 0; i < MAX_IGNORE_LIST; i++) { + if (strcmp(sd->ignore[i].name, nick) == 0) { + WFIFOB(fd,3) = 1; // fail + WFIFOSET(fd, packet_len_table[0x0d1]); + clif_wis_message(fd, wisp_server_name, "This player is already blocked.", strlen("This player is already blocked.") + 1); + if (strcmp(wisp_server_name, nick) == 0) { // to found possible bot users who automaticaly ignore people. + sprintf(output, "Character '%s' (account: %d) has tried AGAIN to block wisps from '%s' (wisp name of the server). Bot user?", sd->status.name, sd->status.account_id, wisp_server_name); + intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, output, strlen(output) + 1); + } + return; + } else if (pos == -1 && sd->ignore[i].name[0] == '\0') + pos = i; + } + // if a position is found and name not found, we add it in the list + if (pos != -1) { + memcpy(sd->ignore[pos].name, nick, 24); + WFIFOB(fd,3) = 0; // success + WFIFOSET(fd, packet_len_table[0x0d1]); + if (strcmp(wisp_server_name, nick) == 0) { // to found possible bot users who automaticaly ignore people. + sprintf(output, "Character '%s' (account: %d) has tried to block wisps from '%s' (wisp name of the server). Bot user?", sd->status.name, sd->status.account_id, wisp_server_name); + intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, output, strlen(output) + 1); + // send something to be inform and force bot to ignore twice... If GM receiving block + block again, it's a bot :) + clif_wis_message(fd, wisp_server_name, "Add me in your ignore list, doesn't block my wisps.", strlen("Add me in your ignore list, doesn't block my wisps.") + 1); + } + } else { + WFIFOB(fd,3) = 1; // fail + WFIFOSET(fd, packet_len_table[0x0d1]); + clif_wis_message(fd, wisp_server_name, "You can not block more people.", strlen("You can not block more people.") + 1); + if (strcmp(wisp_server_name, nick) == 0) { // to found possible bot users who automaticaly ignore people. + sprintf(output, "Character '%s' (account: %d) has tried to block wisps from '%s' (wisp name of the server). Bot user?", sd->status.name, sd->status.account_id, wisp_server_name); + intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, output, strlen(output) + 1); + } + } + // allow action (we remove all same nicks if they exist) + } else { + pos = -1; + for(i = 0; i < MAX_IGNORE_LIST; i++) + if (strcmp(sd->ignore[i].name, nick) == 0) { + memset(sd->ignore[i].name, 0, sizeof(sd->ignore[i].name)); + if (pos != -1) { + WFIFOB(fd,3) = 0; // success + WFIFOSET(fd, packet_len_table[0x0d1]); + pos = i; // don't break, to remove ALL same nick + } + } + if (pos == -1) { + WFIFOB(fd,3) = 1; // fail + WFIFOSET(fd, packet_len_table[0x0d1]); + clif_wis_message(fd, wisp_server_name, "This player is not blocked by you.", strlen("This player is not blocked by you.") + 1); + } + } + } + +// for(i = 0; i < MAX_IGNORE_LIST; i++) // for debug only +// if (sd->ignore[i].name[0] != '\0') +// printf("Ignored player: '%s'\n", sd->ignore[i].name); + + return; +} + +void clif_parse_PMIgnoreAll(int fd, struct map_session_data *sd) { // Rewritten by [Yor] + //printf("Ignore all: state: %d\n", RFIFOB(fd,2)); + if (RFIFOB(fd,2) == 0) {// S 00d0 <type>len.B: 00 (/exall) deny all speech, 01 (/inall) allow all speech + WFIFOW(fd,0) = 0x0d2; // R 00d2 <type>.B <fail>.B: type: 0: deny, 1: allow, fail: 0: success, 1: fail + WFIFOB(fd,2) = 0; + if (sd->ignoreAll == 0) { + sd->ignoreAll = 1; + WFIFOB(fd,3) = 0; // success + WFIFOSET(fd, packet_len_table[0x0d2]); + } else { + WFIFOB(fd,3) = 1; // fail + WFIFOSET(fd, packet_len_table[0x0d2]); + clif_wis_message(fd, wisp_server_name, "You already block everyone.", strlen("You already block everyone.") + 1); + } + } else { + WFIFOW(fd,0) = 0x0d2; // R 00d2 <type>.B <fail>.B: type: 0: deny, 1: allow, fail: 0: success, 1: fail + WFIFOB(fd,2) = 1; + if (sd->ignoreAll == 1) { + sd->ignoreAll = 0; + WFIFOB(fd,3) = 0; // success + WFIFOSET(fd, packet_len_table[0x0d2]); + } else { + WFIFOB(fd,3) = 1; // fail + WFIFOSET(fd, packet_len_table[0x0d2]); + clif_wis_message(fd, wisp_server_name, "You already allow everyone.", strlen("You already allow everyone.") + 1); + } + } + + return; +} + +void clif_parse_skillMessage(int fd, struct map_session_data *sd) { // Added by RoVeRT + int skillid,skilllv, x, y; + char *mes; + + skilllv = RFIFOW(fd,2); + skillid = RFIFOW(fd,4); + + y = RFIFOB(fd,6); + x = RFIFOB(fd,8); + + mes = RFIFOP(fd,10); + + // skill 220 = graffiti +// printf("skill: %d %d location: %3d %3d message: %s\n", skillid, skilllv, x, y, (char*)mes); +} + +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_len_table[0x1d1]); + + return 0; +} + +/*========================================== + * スパノビの/doridoriによるSPR2倍 + *------------------------------------------ + */ +void clif_parse_sn_doridori(int fd, struct map_session_data *sd) { + if (sd) + sd->doridori_counter = 1; + + return; +} +/*========================================== + * スパノビの爆裂波動 + *------------------------------------------ + */ +void clif_parse_sn_explosionspirits(int fd, struct map_session_data *sd) +{ + 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 + *------------------------------------------ + */ +void clif_friends_list_send(struct map_session_data *sd) { + int i, n; + + // Send friends list + n = 0; + WFIFOW(sd->fd, 0) = 0x201; + for(i = 0; i < 20; i++) + if (sd->status.friend_id[i]) { + WFIFOL(sd->fd,4 + 32 * n + 1) = sd->status.friend_id[i]; + //WFIFOB(sd->fd,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(WFIFOP(sd->fd,4 + 32 * n + 8), &sd->status.friend_name[i], 23); + n++; + } + WFIFOW(sd->fd,2) = 4 + 32 * n; + WFIFOSET(sd->fd, WFIFOW(sd->fd,2)); +} + +void clif_parse_friends_list_add(int fd, struct map_session_data *sd) { + struct map_session_data *f_sd; + int i; + + f_sd = map_nick2sd(RFIFOP(fd,2)); + + // Friend doesn't exist (no player with this name) + if (f_sd == NULL) { + clif_displaymessage(fd, "This name (for a friend) doesn't exist."); + return; + } + + // Friend already exists + for (i = 0; i < 20; i++) + if (sd->status.friend_id[i] == f_sd->status.char_id) { + clif_displaymessage(fd, "Friend already exists."); + return; + } + + // Find an empty slot + for (i = 0; i < 20; i++) + if (sd->status.friend_id[i] == 0) + break; + if (i == 20) { + clif_displaymessage(fd, "Friends list is full."); + return; + } + + sd->status.friend_id[i] = f_sd->status.char_id; + memset(sd->status.friend_name[i], 0, sizeof(sd->status.friend_name[i])); + memcpy(sd->status.friend_name[i], f_sd->status.name, 23); + clif_displaymessage(fd, "Friend added."); + + clif_friends_list_send(sd); + + //printf("clif_parse_friends_list_add"); + + return; +} + +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); + int i, j; + + // Search friend + for (i = 0; i < 20; i ++) + if (sd->status.friend_id[i] == id) { + // move all chars down + for(j = i + 1; j < 20; j++) { + sd->status.friend_id[j-1] = sd->status.friend_id[j]; + memcpy(sd->status.friend_name[j-1], sd->status.friend_name[j], sizeof(sd->status.friend_name[j])); + } + sd->status.friend_id[19] = 0; + memset(sd->status.friend_name[19], 0, sizeof(sd->status.friend_name[19])); + clif_displaymessage(fd, "Friend removed"); + clif_friends_list_send(sd); + break; + } + + if (i == 20) + clif_displaymessage(fd, "Name not found in list."); + + return; +} + +/*========================================== + * /killall + *------------------------------------------ + */ +void clif_parse_GMkillall(int fd,struct map_session_data *sd) +{ + char message[50]; + + nullpo_retv(sd); + + strncpy(message,sd->status.name, 24); + is_atcommand(fd, sd, strcat(message," : @kickall"),0); + + return; +} + +// functions list +static void (*clif_parse_func_table[7][0x220])() = { + { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + // 40 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + // 70 + NULL, NULL, clif_parse_WantToConnection, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, clif_parse_LoadEndAck, clif_parse_TickSend, NULL, + + // 80 + NULL, NULL, NULL, NULL, NULL, clif_parse_WalkToXY, NULL, NULL, + NULL, clif_parse_ActionRequest, NULL, NULL, clif_parse_GlobalMessage, NULL, NULL, NULL, + // 90 + clif_parse_NpcClicked, NULL, NULL, NULL, clif_parse_GetCharNameRequest, NULL, clif_parse_Wis, NULL, + NULL, clif_parse_GMmessage, NULL, clif_parse_ChangeDir, NULL, NULL, NULL, clif_parse_TakeItem, + // a0 + NULL, NULL, clif_parse_DropItem, NULL, NULL, NULL, NULL, clif_parse_UseItem, + NULL, clif_parse_EquipItem, NULL, clif_parse_UnequipItem, NULL, NULL, NULL, NULL, + // b0 + NULL, NULL, clif_parse_Restart, NULL, NULL, NULL, NULL, NULL, + clif_parse_NpcSelectMenu, clif_parse_NpcNextClicked, NULL, clif_parse_StatusUp, NULL, NULL, NULL, clif_parse_Emotion, + + // c0 + NULL, clif_parse_HowManyConnections, NULL, NULL, NULL, clif_parse_NpcBuySellSelected, NULL, NULL, + clif_parse_NpcBuyListSend, clif_parse_NpcSellListSend, NULL, NULL, clif_parse_GMKick, NULL, clif_parse_GMkillall, clif_parse_PMIgnore, + // d0 + clif_parse_PMIgnoreAll, NULL, NULL, NULL, NULL, clif_parse_CreateChatRoom, NULL, NULL, + NULL, clif_parse_ChatAddMember, NULL, NULL, NULL, NULL, clif_parse_ChatRoomStatusChange, NULL, + // e0 + clif_parse_ChangeChatOwner, NULL, clif_parse_KickFromChat, clif_parse_ChatLeave, clif_parse_TradeRequest, NULL, clif_parse_TradeAck, NULL, + clif_parse_TradeAddItem, NULL, NULL, clif_parse_TradeOk, NULL, clif_parse_TradeCansel, NULL, clif_parse_TradeCommit, + // f0 + NULL, NULL, NULL, clif_parse_MoveToKafra, NULL, clif_parse_MoveFromKafra, NULL, clif_parse_CloseKafra, + NULL, clif_parse_CreateParty, NULL, NULL, clif_parse_PartyInvite, NULL, NULL, clif_parse_ReplyPartyInvite, + + // 100 + clif_parse_LeaveParty, NULL, clif_parse_PartyChangeOption, clif_parse_RemovePartyMember, NULL, NULL, NULL, NULL, + clif_parse_PartyMessage, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + // 110 + NULL, NULL, clif_parse_SkillUp, clif_parse_UseSkillToId, NULL, NULL, clif_parse_UseSkillToPos, NULL, + clif_parse_StopAttack, NULL, NULL, clif_parse_UseSkillMap, NULL, clif_parse_RequestMemo, NULL, NULL, + // 120 + NULL, NULL, NULL, NULL, NULL, NULL, clif_parse_PutItemToCart, clif_parse_GetItemFromCart, + clif_parse_MoveFromKafraToCart, clif_parse_MoveToKafraFromCart, clif_parse_RemoveOption, NULL, NULL, NULL, clif_parse_CloseVending, NULL, + // 130 + clif_parse_VendingListReq, NULL, NULL, NULL, clif_parse_PurchaseReq, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, clif_parse_GM_Monster_Item, + + // 140 + clif_parse_MapMove, NULL, NULL, clif_parse_NpcAmountInput, NULL, NULL, clif_parse_NpcCloseClicked, NULL, + NULL, clif_parse_GMReqNoChat, NULL, NULL, NULL, clif_parse_GuildCheckMaster, NULL, clif_parse_GuildReqeustInfo, + // 150 + NULL, clif_parse_GuildRequestEmblem, NULL, clif_parse_GuildChangeEmblem, NULL, clif_parse_GuildChangeMemberPosition, NULL, NULL, + NULL, clif_parse_GuildLeave, NULL, clif_parse_GuildExplusion, NULL, clif_parse_GuildBreak, NULL, NULL, + // 160 + NULL, clif_parse_GuildChangePositionInfo, NULL, NULL, NULL, clif_parse_CreateGuild, NULL, NULL, + clif_parse_GuildInvite, NULL, NULL, clif_parse_GuildReplyInvite, NULL, NULL, clif_parse_GuildChangeNotice, NULL, + // 170 + clif_parse_GuildRequestAlliance, NULL, clif_parse_GuildReplyAlliance, NULL, NULL, NULL, NULL, NULL, + clif_parse_ItemIdentify, NULL, clif_parse_UseCard, NULL, clif_parse_InsertCard, NULL, clif_parse_GuildMessage, NULL, + + // 180 + clif_parse_GuildOpposition, NULL, NULL, clif_parse_GuildDelAlliance, NULL, NULL, NULL, NULL, + NULL, NULL, clif_parse_QuitGame, NULL, NULL, NULL, clif_parse_ProduceMix, NULL, + // 190 + clif_parse_UseSkillToPos, NULL, NULL, clif_parse_SolveCharName, NULL, NULL, NULL, clif_parse_ResetChar, + NULL, NULL, NULL, NULL, clif_parse_LGMmessage, clif_parse_GMHide, NULL, clif_parse_CatchPet, + // 1a0 + NULL, clif_parse_PetMenu, NULL, NULL, NULL, clif_parse_ChangePetName, NULL, clif_parse_SelectEgg, + NULL, clif_parse_SendEmotion, NULL, NULL, NULL, NULL, clif_parse_SelectArrow, clif_parse_ChangeCart, + // 1b0 + NULL, NULL, clif_parse_OpenVending, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, clif_parse_Shift, clif_parse_Shift, clif_parse_Recall, clif_parse_Recall, NULL, NULL, + + // 1c0 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, clif_parse_AutoSpell, + NULL, + // 1d0 + NULL, NULL, NULL, NULL, NULL, clif_parse_NpcStringInput, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, clif_parse_GMReqNoChatCount, + // 1e0 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, clif_parse_sn_doridori, + clif_parse_CreateParty2, NULL, NULL, NULL, NULL, clif_parse_sn_explosionspirits, NULL, NULL, + // 1f0 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + // 200 + NULL, NULL, clif_parse_friends_list_add, clif_parse_friends_list_remove, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + // 210 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +#if 0 + case 0xd3: clif_parse_IgnoreList +#endif + }, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL}, + {NULL} +}; + +/*========================================== + * クライアントからのパケット解析 + * socket.cのdo_parsepacketから呼び出される + *------------------------------------------ + */ +static int clif_parse(int fd) { + int packet_len = 0, cmd, packet_ver; + struct map_session_data *sd; + + sd = session[fd]->session_data; + + // 接続が切れてるので後始末 + if (!chrif_isconnect() || session[fd]->eof) { // char鯖に繋がってない間は接続禁止 (!chrif_isconnect()) + if (sd && sd->state.auth) { + if (chrif_isconnect()) + clif_quitsave(fd, sd); + if (sd->status.name != NULL) + printf("Player [%s] has logged off your server.\n", sd->status.name); // Player logout display [Valaris] + else + printf("Player with account [%d] has logged off your server.\n", sd->bl.id); // Player logout display [Yor] + } 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; + + //printf("clif_parse: connection #%d, packet: 0x%x (with being read: %d bytes).\n", fd, RFIFOW(fd,0), RFIFOREST(fd)); + + 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; + } + + // get packet version before to parse + packet_ver = 0; + if (sd) + packet_ver = sd->packet_ver; + // check authentification packet to know packet version + else { + // 0x72 + if (cmd == 0x72) { + if (RFIFOREST(fd) >= 39 && (RFIFOB(fd,38) == 0 || RFIFOB(fd,38) == 1)) // 00 = Female, 01 = Male + packet_ver = 7; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + else if (RFIFOREST(fd) >= 22 && (RFIFOB(fd,21) == 0 || RFIFOB(fd,21) == 1)) // 00 = Female, 01 = Male + packet_ver = 6; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + else if (RFIFOREST(fd) >= 19 && (RFIFOB(fd,18) == 0 || RFIFOB(fd,18) == 1)) // 00 = Female, 01 = Male + packet_ver = 5; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + // else probably incomplete packet + else if (RFIFOREST(fd) < 19) + return 0; + // 0x7E + } else if (cmd == 0x7E) { + if (RFIFOREST(fd) >= 37 && (RFIFOB(fd,36) == 0 || RFIFOB(fd,36) == 1)) // 00 = Female, 01 = Male + packet_ver = 9; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + else if (RFIFOREST(fd) >= 33 && (RFIFOB(fd,32) == 0 || RFIFOB(fd,32) == 1)) // 00 = Female, 01 = Male + packet_ver = 8; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + // else probably incomplete packet + else if (RFIFOREST(fd) < 33) + return 0; + // 0xF5 + } else { + if (RFIFOREST(fd) >= 34 && (RFIFOB(fd,33) == 0 || RFIFOB(fd,33) == 1)) // 00 = Female, 01 = Male + packet_ver = 10; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + else if (RFIFOREST(fd) >= 33 && (RFIFOB(fd,32) == 0 || RFIFOB(fd,32) == 1)) // 00 = Female, 01 = Male + packet_ver = 12; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + else if (RFIFOREST(fd) >= 32 && (RFIFOB(fd,31) == 0 || RFIFOB(fd,31) == 1)) // 00 = Female, 01 = Male + packet_ver = 11; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + else if (RFIFOREST(fd) >= 29 && (RFIFOB(fd,28) == 0 || RFIFOB(fd,28) == 1)) // 00 = Female, 01 = Male + packet_ver = 13; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) + // else probably incomplete packet + else if (RFIFOREST(fd) < 29) + return 0; + } + // check if version is accepted + if ((packet_ver == 5 && (battle_config.packet_ver_flag & 1) == 0) || + (packet_ver == 6 && (battle_config.packet_ver_flag & 2) == 0) || + (packet_ver == 7 && (battle_config.packet_ver_flag & 4) == 0) || + (packet_ver == 8 && (battle_config.packet_ver_flag & 8) == 0) || + (packet_ver == 9 && (battle_config.packet_ver_flag & 16) == 0) || + (packet_ver == 10 && (battle_config.packet_ver_flag & 32) == 0) || + (packet_ver == 11 && (battle_config.packet_ver_flag & 64) == 0) || + (packet_ver == 12 && (battle_config.packet_ver_flag & 128) == 0) || + (packet_ver == 13 && (battle_config.packet_ver_flag & 256) == 0)) { + WFIFOW(fd,0) = 0x6a; + WFIFOB(fd,2) = 5; // 05 = Game's EXE is not the latest version + WFIFOSET(fd,23); + session[fd]->eof = 1; + return 0; + } + } + + // ゲーム用以外パケットか、認証を終える前に0072以外が来たら、切断する + if (packet_ver < 5 || packet_ver > 13 || // if packet is not inside these values: session is incorrect?? or auth packet is unknown + cmd >= 0x220 || packet_size_table[packet_ver-5][cmd] == 0) { + if (!fd) + return 0; + session[fd]->eof = 1; + printf("clif_parse: session #%d, packet 0x%x (%d bytes received) -> disconnected.\n", fd, cmd, RFIFOREST(fd)); + return 0; + } + + // パケット長を計算 + packet_len = packet_size_table[packet_ver-5][cmd]; + if (packet_len == -1) { + if (RFIFOREST(fd) < 4) + return 0; // 可変長パケットで長さの所までデータが来てない + packet_len = RFIFOW(fd,2); + if (packet_len < 4 || packet_len > 32768) { + 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_ver < 8 && clif_parse_func_table[0][cmd]) { // packet version 5-6-7 use same functions, but size are different + // パケット処理 + clif_parse_func_table[0][cmd](fd, sd); + } else if (packet_ver >= 8 && clif_parse_func_table[packet_ver - 7][cmd]) { + // パケット処理 + clif_parse_func_table[packet_ver - 7][cmd](fd, sd); + } 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; +} + +/*========================================== + * + *------------------------------------------ + */ +int do_init_clif(void) { +#ifndef __WIN32 + int i; +#endif + + // functions of packet version 5-6-7 are same, but size are different + // init packet function calls for packet ver 8 + memcpy(clif_parse_func_table[1], clif_parse_func_table[0], sizeof(clif_parse_func_table[0])); + clif_parse_func_table[1][0x072] = clif_parse_DropItem; + clif_parse_func_table[1][0x07e] = clif_parse_WantToConnection; + clif_parse_func_table[1][0x085] = clif_parse_UseSkillToId; + clif_parse_func_table[1][0x089] = clif_parse_GetCharNameRequest; + clif_parse_func_table[1][0x08c] = clif_parse_UseSkillToPos; + clif_parse_func_table[1][0x094] = clif_parse_TakeItem; + clif_parse_func_table[1][0x09b] = clif_parse_WalkToXY; + clif_parse_func_table[1][0x09f] = clif_parse_ChangeDir; + clif_parse_func_table[1][0x0a2] = clif_parse_UseSkillToPos; + clif_parse_func_table[1][0x0a7] = clif_parse_SolveCharName; + clif_parse_func_table[1][0x0f3] = clif_parse_GlobalMessage; + clif_parse_func_table[1][0x0f5] = clif_parse_UseItem; + clif_parse_func_table[1][0x0f7] = clif_parse_TickSend; + clif_parse_func_table[1][0x113] = clif_parse_MoveToKafra; + clif_parse_func_table[1][0x116] = clif_parse_CloseKafra; + clif_parse_func_table[1][0x190] = clif_parse_MoveFromKafra; + clif_parse_func_table[1][0x193] = clif_parse_ActionRequest; + // init packet function calls for packet ver 9 (same function of packet version 8, but size are different) + memcpy(clif_parse_func_table[2], clif_parse_func_table[1], sizeof(clif_parse_func_table[0])); + // init packet function calls for packet ver 10 + memcpy(clif_parse_func_table[3], clif_parse_func_table[2], sizeof(clif_parse_func_table[0])); + clif_parse_func_table[3][0x072] = clif_parse_UseItem; + clif_parse_func_table[3][0x07e] = clif_parse_MoveToKafra; + clif_parse_func_table[3][0x085] = clif_parse_ActionRequest; + clif_parse_func_table[3][0x089] = clif_parse_WalkToXY; + clif_parse_func_table[3][0x08c] = clif_parse_UseSkillToPos; + clif_parse_func_table[3][0x094] = clif_parse_DropItem; + clif_parse_func_table[3][0x09b] = clif_parse_GetCharNameRequest; + clif_parse_func_table[3][0x09f] = clif_parse_GlobalMessage; + clif_parse_func_table[3][0x0a2] = clif_parse_SolveCharName; + clif_parse_func_table[3][0x0a7] = clif_parse_UseSkillToPos; + clif_parse_func_table[3][0x0f3] = clif_parse_ChangeDir; + clif_parse_func_table[3][0x0f5] = clif_parse_WantToConnection; + clif_parse_func_table[3][0x0f7] = clif_parse_CloseKafra; + clif_parse_func_table[3][0x113] = clif_parse_TakeItem; + clif_parse_func_table[3][0x116] = clif_parse_TickSend; + clif_parse_func_table[3][0x190] = clif_parse_UseSkillToId; + clif_parse_func_table[3][0x193] = clif_parse_MoveFromKafra; + // init packet function calls for packet ver 11 (same function of packet version 10, but size are different) + memcpy(clif_parse_func_table[4], clif_parse_func_table[3], sizeof(clif_parse_func_table[0])); + // init packet function calls for packet ver 12 (same function of packet version 11, but size are different) + memcpy(clif_parse_func_table[5], clif_parse_func_table[4], sizeof(clif_parse_func_table[0])); + // init packet function calls for packet ver 13 (same function of packet version 12, but size are different) + memcpy(clif_parse_func_table[6], clif_parse_func_table[5], sizeof(clif_parse_func_table[0])); + + // size of packet version 5 + memcpy(&packet_size_table[0], &packet_len_table, sizeof(packet_len_table)); + // size of packet version 6 + memcpy(&packet_size_table[1], &packet_size_table[0], sizeof(packet_len_table)); + packet_size_table[1][0x072] = 22; + packet_size_table[1][0x085] = 8; + packet_size_table[1][0x0a7] = 13; + packet_size_table[1][0x113] = 15; + packet_size_table[1][0x116] = 15; + packet_size_table[1][0x190] = 95; + // size of packet version 7 + memcpy(&packet_size_table[2], &packet_size_table[1], sizeof(packet_len_table)); + packet_size_table[2][0x072] = 39; + packet_size_table[2][0x085] = 9; + packet_size_table[2][0x09b] = 13; + packet_size_table[2][0x09f] = 10; + packet_size_table[2][0x0a7] = 17; + packet_size_table[2][0x113] = 19; + packet_size_table[2][0x116] = 19; + packet_size_table[2][0x190] = 99; + // size of packet version 8 + memcpy(&packet_size_table[3], &packet_size_table[2], sizeof(packet_len_table)); + packet_size_table[3][0x072] = 14; + packet_size_table[3][0x07e] = 33; + packet_size_table[3][0x085] = 20; + packet_size_table[3][0x089] = 15; + packet_size_table[3][0x08c] = 23; + packet_size_table[3][0x094] = 10; + packet_size_table[3][0x09b] = 6; + packet_size_table[3][0x09f] = 13; + packet_size_table[3][0x0a2] = 103; + packet_size_table[3][0x0a7] = 12; + packet_size_table[3][0x0f3] = -1; + packet_size_table[3][0x0f5] = 17; + packet_size_table[3][0x0f7] = 10; + packet_size_table[3][0x113] = 16; + packet_size_table[3][0x116] = 2; + packet_size_table[3][0x190] = 26; + packet_size_table[3][0x193] = 9; + // size of packet version 9 + memcpy(&packet_size_table[4], &packet_size_table[3], sizeof(packet_len_table)); + packet_size_table[4][0x072] = 17; + packet_size_table[4][0x07e] = 37; + packet_size_table[4][0x085] = 26; + packet_size_table[4][0x089] = 12; + packet_size_table[4][0x08c] = 40; + packet_size_table[4][0x094] = 13; + packet_size_table[4][0x09b] = 15; + packet_size_table[4][0x09f] = 12; + packet_size_table[4][0x0a2] = 120; + packet_size_table[4][0x0a7] = 11; +// packet_size_table[4][0x0f3] = -1; + packet_size_table[4][0x0f5] = 24; + packet_size_table[4][0x0f7] = 13; + packet_size_table[4][0x113] = 23; +// packet_size_table[4][0x116] = 2; + packet_size_table[4][0x190] = 26; + packet_size_table[4][0x193] = 18; + // new packet + packet_size_table[4][0x20f] = 10; + packet_size_table[4][0x210] = 22; + packet_size_table[4][0x212] = 26; + packet_size_table[4][0x213] = 26; + packet_size_table[4][0x214] = 42; + // size of packet version 10 + memcpy(&packet_size_table[5], &packet_size_table[4], sizeof(packet_len_table)); + packet_size_table[5][0x072] = 20; + packet_size_table[5][0x07e] = 19; + packet_size_table[5][0x085] = 23; + packet_size_table[5][0x089] = 9; + packet_size_table[5][0x08c] = 105; + packet_size_table[5][0x094] = 17; + packet_size_table[5][0x09b] = 14; + packet_size_table[5][0x09f] = -1; + packet_size_table[5][0x0a2] = 14; + packet_size_table[5][0x0a7] = 25; + packet_size_table[5][0x0f3] = 10; + packet_size_table[5][0x0f5] = 34; + packet_size_table[5][0x0f7] = 2; + packet_size_table[5][0x113] = 11; + packet_size_table[5][0x116] = 11; + packet_size_table[5][0x190] = 22; + packet_size_table[5][0x193] = 17; + // size of packet version 11 + memcpy(&packet_size_table[6], &packet_size_table[5], sizeof(packet_len_table)); + packet_size_table[6][0x072] = 18; + packet_size_table[6][0x07e] = 25; + packet_size_table[6][0x085] = 9; + packet_size_table[6][0x089] = 14; + packet_size_table[6][0x08c] = 109; + packet_size_table[6][0x094] = 19; + packet_size_table[6][0x09b] = 10; +// packet_size_table[6][0x09f] = -1; + packet_size_table[6][0x0a2] = 10; + packet_size_table[6][0x0a7] = 29; + packet_size_table[6][0x0f3] = 18; + packet_size_table[6][0x0f5] = 32; +// packet_size_table[6][0x0f7] = 2; + packet_size_table[6][0x113] = 14; + packet_size_table[6][0x116] = 14; + packet_size_table[6][0x190] = 14; + packet_size_table[6][0x193] = 12; + // size of packet version 12 + memcpy(&packet_size_table[7], &packet_size_table[6], sizeof(packet_len_table)); + packet_size_table[7][0x072] = 17; + packet_size_table[7][0x07e] = 16; +// packet_size_table[7][0x085] = 9; + packet_size_table[7][0x089] = 6; + packet_size_table[7][0x08c] = 103; + packet_size_table[7][0x094] = 14; + packet_size_table[7][0x09b] = 15; +// packet_size_table[7][0x09f] = -1; + packet_size_table[7][0x0a2] = 12; + packet_size_table[7][0x0a7] = 23; + packet_size_table[7][0x0f3] = 13; + packet_size_table[7][0x0f5] = 33; +// packet_size_table[7][0x0f7] = 2; + packet_size_table[7][0x113] = 10; + packet_size_table[7][0x116] = 10; + packet_size_table[7][0x190] = 20; + packet_size_table[7][0x193] = 26; + // size of packet version 13 + memcpy(&packet_size_table[8], &packet_size_table[7], sizeof(packet_len_table)); + packet_size_table[8][0x072] = 13; + packet_size_table[8][0x07e] = 13; + packet_size_table[8][0x085] = 15; +// packet_size_table[8][0x089] = 6; + packet_size_table[8][0x08c] = 108; + packet_size_table[8][0x094] = 12; + packet_size_table[8][0x09b] = 10; +// packet_size_table[8][0x09f] = -1; + packet_size_table[8][0x0a2] = 16; + packet_size_table[8][0x0a7] = 28; + packet_size_table[8][0x0f3] = 15; + packet_size_table[8][0x0f5] = 29; +// packet_size_table[8][0x0f7] = 2; + packet_size_table[8][0x113] = 9; + packet_size_table[8][0x116] = 9; + packet_size_table[8][0x190] = 26; + packet_size_table[8][0x193] = 22; + + set_defaultparse(clif_parse); +#ifdef __WIN32 + if (!make_listen_port(map_port)) { + printf("cant bind game port\n"); + exit(1); + } +#else + for(i = 0; i < 10; i++) { + if (make_listen_port(map_port)) + break; + sleep(20); + } + if (i == 10) { + printf("cant bind game port\n"); + exit(1); + } +#endif + + 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 index 95c982d72..595c7f7be 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -1,287 +1,287 @@ -// $Id: clif.h 1952 2004-10-23 14:05:01Z Yor $
-#ifndef _CLIF_H_
-#define _CLIF_H_
-
-#ifdef __WIN32
-typedef unsigned int in_addr_t;
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#endif
-
-#include "map.h"
-
-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
-
-
+// $Id: clif.h 1952 2004-10-23 14:05:01Z Yor $ +#ifndef _CLIF_H_ +#define _CLIF_H_ + +#ifdef __WIN32 +typedef unsigned int in_addr_t; +#else +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#endif + +#include "map.h" + +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 index 164cf9827..fc13adcf0 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -1,1554 +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);
-}
+// $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 index 46842464f..528605f7f 100644 --- a/src/map/guild.h +++ b/src/map/guild.h @@ -1,87 +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
+// $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 index 3c130623c..62a2bd761 100644 --- a/src/map/intif.c +++ b/src/map/intif.c @@ -1,1125 +1,1125 @@ -// $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,14);
- 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=0; //,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 && strcmp(sd->status.name, RFIFOP(fd,32)) == 0){
-/*
- for(i=0;i<MAX_WIS_REFUSAL;i++){ //拒否リストに名前があるかどうか判定してあれば拒否
- if(strcmp(sd->wis_refusal[i],RFIFOP(fd,8))==0){
- j++;
- break;
- }
- }
-*/
- if(sd->ignoreAll == 1)
- intif_wis_replay(RFIFOL(fd,4), 2); // 受信拒否
-/*
- else if(j>0)
- intif_wis_replay(id,2); // 受信拒否
-
- else{
-*/
- if(i == MAX_IGNORE_LIST) {
- clif_wis_message(sd->fd,RFIFOP(fd,8),RFIFOP(fd,56),RFIFOW(fd,2)-56);
- intif_wis_replay(RFIFOL(fd,4),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;
-}
+// $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,14); + 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=0; //,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 && strcmp(sd->status.name, RFIFOP(fd,32)) == 0){ +/* + for(i=0;i<MAX_WIS_REFUSAL;i++){ //拒否リストに名前があるかどうか判定してあれば拒否 + if(strcmp(sd->wis_refusal[i],RFIFOP(fd,8))==0){ + j++; + break; + } + } +*/ + if(sd->ignoreAll == 1) + intif_wis_replay(RFIFOL(fd,4), 2); // 受信拒否 +/* + else if(j>0) + intif_wis_replay(id,2); // 受信拒否 + + else{ +*/ + if(i == MAX_IGNORE_LIST) { + clif_wis_message(sd->fd,RFIFOP(fd,8),RFIFOP(fd,56),RFIFOW(fd,2)-56); + intif_wis_replay(RFIFOL(fd,4),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 index bb5fcd379..3fe14f2e4 100644 --- a/src/map/intif.h +++ b/src/map/intif.h @@ -1,60 +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
+// $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 index 095e053c2..a225cff83 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -1,882 +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;
-}
+// $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 index 05ecc572f..0edfad243 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -1,84 +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
+// $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 index b8997a7df..6c0b01905 100644 --- a/src/map/log.c +++ b/src/map/log.c @@ -1,243 +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;
-}
+// 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 index 7047d980c..4e34ef0cc 100644 --- a/src/map/log.h +++ b/src/map/log.h @@ -1,27 +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
+#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 index c6155a04d..019f6303d 100644 --- a/src/map/mail.c +++ b/src/map/mail.c @@ -1,324 +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;
-}
-
+// 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 index cfa86c6bb..6bd8e510c 100644 --- a/src/map/mail.h +++ b/src/map/mail.h @@ -1,9 +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);
+// 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 index 217f36c88..21ee089ea 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -1,2208 +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;
-}
+// $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 index d622ecd35..8596f781b 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -1,726 +1,726 @@ -// $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_IGNORE_LIST 80
-
-#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;
-
- struct{
- char name[24];
- } ignore[MAX_IGNORE_LIST];
- int ignoreAll;
-
- 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
+// $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_IGNORE_LIST 80 + +#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; + + struct{ + char name[24]; + } ignore[MAX_IGNORE_LIST]; + int ignoreAll; + + 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 index a340d171e..f4032662f 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -1,4273 +1,4273 @@ -// $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)) && (i++) < 2000);
- if(i>=2000){
- class=mob_db[0].summonper[j];
- }
- }else{
- return 0;
- }
-// if(battle_config.etc_log)
-// 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) md->mode=0x1+0x4+0x80; //移動してアクティブで反撃する
- md->m =m;
- md->x0=x;
- md->y0=y;
- md->xs=0;
- md->ys=0;
- md->spawndelay1=-1; // 一度のみフラグ
- md->spawndelay2=-1; // 一度のみフラグ
-
- 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) // 値が異常なら召喚を止める
- 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){ // 検索に失敗したので以前に沸いた場所を使う
- x=lx;
- y=ly;
- }else
- return 0; // 最初に沸く場所の検索を失敗したのでやめる
- }
- 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); // スキルユニットの検査
- }
- 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); // とまったときに位置の再送信
- }
- 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); // ステータス異常を解除する
- skill_clear_unitgroup(&md->bl); // 全てのスキルユニットグループを削除する
- 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!=BL_MOB)
- return 1;
-
- if(md->timer != tid){
- if(battle_config.error_log)
- 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)
- 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->guild_id = 0;
- if (md->class >= 1285 && md->class <= 1288) {
- struct guild_castle *gc=guild_mapname2gc(map[md->bl.m].name);
- if(gc)
- md->guild_id = gc->guild_id;
- }
-
- 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 <= 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){
- nullpo_retr(0, sd=(struct map_session_data *)bl);
- if(!gc)
- return 0;
- if(gc && sd && sd->status.guild_id) {
- g=guild_search(sd->status.guild_id); // don't attack guild members [Valaris]
- if(g && 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 ) // 同じマス
- 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)
- 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){
- 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->bl.type!=BL_MOB)
- 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){
- 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){
- 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)
- 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) {
- 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)
- 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)
- 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)
-// 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)
- 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)
- 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) {
- 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) {
- 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)
- 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)
- 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)
- 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;
-}
+// $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)) && (i++) < 2000); + if(i>=2000){ + class=mob_db[0].summonper[j]; + } + }else{ + return 0; + } +// if(battle_config.etc_log) +// 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) md->mode=0x1+0x4+0x80; //移動してアクティブで反撃する + md->m =m; + md->x0=x; + md->y0=y; + md->xs=0; + md->ys=0; + md->spawndelay1=-1; // 一度のみフラグ + md->spawndelay2=-1; // 一度のみフラグ + + 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) // 値が異常なら召喚を止める + 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){ // 検索に失敗したので以前に沸いた場所を使う + x=lx; + y=ly; + }else + return 0; // 最初に沸く場所の検索を失敗したのでやめる + } + 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); // スキルユニットの検査 + } + 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); // とまったときに位置の再送信 + } + 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); // ステータス異常を解除する + skill_clear_unitgroup(&md->bl); // 全てのスキルユニットグループを削除する + 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!=BL_MOB) + return 1; + + if(md->timer != tid){ + if(battle_config.error_log) + 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) + 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->guild_id = 0; + if (md->class >= 1285 && md->class <= 1288) { + struct guild_castle *gc=guild_mapname2gc(map[md->bl.m].name); + if(gc) + md->guild_id = gc->guild_id; + } + + 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 <= 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){ + nullpo_retr(0, sd=(struct map_session_data *)bl); + if(!gc) + return 0; + if(gc && sd && sd->status.guild_id) { + g=guild_search(sd->status.guild_id); // don't attack guild members [Valaris] + if(g && 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 ) // 同じマス + 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) + 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){ + 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->bl.type!=BL_MOB) + 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){ + 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){ + 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) + 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) { + 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) + 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) + 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) +// 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) + 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) + 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) { + 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) { + 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) + 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) + 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) + 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 index 2ec71d90c..e5a83be0f 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -1,139 +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
+// $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 index 1c089a2c9..65974aee8 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -1,2274 +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;
-}
+// $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 index 9bc7a6c96..4f0c43cba 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -1,52 +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
-
+// $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 index d433fa3b8..7d8cdafe2 100644 --- a/src/map/party.c +++ b/src/map/party.c @@ -1,644 +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);
-}
+// $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 index e1a03fcd1..28d8096f7 100644 --- a/src/map/party.h +++ b/src/map/party.h @@ -1,47 +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
+// $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 index 51143c943..b2e0a78a8 100644 --- a/src/map/path.c +++ b/src/map/path.c @@ -1,404 +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
+// $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 index a05672b13..83116add7 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1,7524 +1,7524 @@ -// $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);
- nullpo_retr(1, sd);
-
- 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((skill=pc_checkskill(sd,BS_HILTBINDING))>0) { // Hilt binding gives +1 str +4 atk
- sd->paramb[4] ++;
- sd->base_atk += 4;
- }
-
- // ステータス変化による基本パラメータ補正
- 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;
- int agib = (sd->status.agi+sd->paramb[1]+sd->parame[1])*(sd->sc_data[SC_QUAGMIRE].val1*10)/100;
- int dexb = (sd->status.dex+sd->paramb[4]+sd->parame[4])*(sd->sc_data[SC_QUAGMIRE].val1*10)/100;
- sd->paramb[1]-= agib > 50 ? 50 : agib;
- sd->paramb[4]-= dexb > 50 ? 50 : dexb;
- }
- 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;
- }
- if(sd->sc_data[SC_MARIONETTE].timer!=-1){
- sd->paramb[0]-= (sd->status.str+sd->paramb[0]+sd->parame[0])/2;
- sd->paramb[1]-= (sd->status.agi+sd->paramb[1]+sd->parame[1])/2;
- sd->paramb[2]-= (sd->status.vit+sd->paramb[2]+sd->parame[2])/2;
- sd->paramb[3]-= (sd->status.int_+sd->paramb[3]+sd->parame[3])/2;
- sd->paramb[4]-= (sd->status.dex+sd->paramb[4]+sd->parame[4])/2;
- sd->paramb[5]-= (sd->status.luk+sd->paramb[5]+sd->parame[5])/2;
- }
- }
-
- //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 += 10000;
- }
- 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[0] += skill;
- sd->subele[3] += skill*5;
- }
-
- 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*1.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+5*sd->sc_data[SC_MAGICPOWER].val1)/100;
- sd->matk2 = sd->matk2*(100+5*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->sc_data[SC_KEEPING].timer!=-1)
- sd->def = 100;
- if(sd->sc_data[SC_BARRIER].timer!=-1)
- sd->mdef = 100;
- }
-
- 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);
- else if(sd->sc_data[SC_ENDURE].timer != -1 && src->type==BL_MOB) // [Celest]
- if((--sd->sc_data[SC_ENDURE].val2) <= 0)
- skill_status_change_end(&sd->bl, SC_ENDURE, -1);
- // 演奏/ダンスの中断
- 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;
-}
+// $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); + nullpo_retr(1, sd); + + 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((skill=pc_checkskill(sd,BS_HILTBINDING))>0) { // Hilt binding gives +1 str +4 atk + sd->paramb[4] ++; + sd->base_atk += 4; + } + + // ステータス変化による基本パラメータ補正 + 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; + int agib = (sd->status.agi+sd->paramb[1]+sd->parame[1])*(sd->sc_data[SC_QUAGMIRE].val1*10)/100; + int dexb = (sd->status.dex+sd->paramb[4]+sd->parame[4])*(sd->sc_data[SC_QUAGMIRE].val1*10)/100; + sd->paramb[1]-= agib > 50 ? 50 : agib; + sd->paramb[4]-= dexb > 50 ? 50 : dexb; + } + 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; + } + if(sd->sc_data[SC_MARIONETTE].timer!=-1){ + sd->paramb[0]-= (sd->status.str+sd->paramb[0]+sd->parame[0])/2; + sd->paramb[1]-= (sd->status.agi+sd->paramb[1]+sd->parame[1])/2; + sd->paramb[2]-= (sd->status.vit+sd->paramb[2]+sd->parame[2])/2; + sd->paramb[3]-= (sd->status.int_+sd->paramb[3]+sd->parame[3])/2; + sd->paramb[4]-= (sd->status.dex+sd->paramb[4]+sd->parame[4])/2; + sd->paramb[5]-= (sd->status.luk+sd->paramb[5]+sd->parame[5])/2; + } + } + + //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 += 10000; + } + 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[0] += skill; + sd->subele[3] += skill*5; + } + + 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*1.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+5*sd->sc_data[SC_MAGICPOWER].val1)/100; + sd->matk2 = sd->matk2*(100+5*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->sc_data[SC_KEEPING].timer!=-1) + sd->def = 100; + if(sd->sc_data[SC_BARRIER].timer!=-1) + sd->mdef = 100; + } + + 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); + else if(sd->sc_data[SC_ENDURE].timer != -1 && src->type==BL_MOB) // [Celest] + if((--sd->sc_data[SC_ENDURE].val2) <= 0) + skill_status_change_end(&sd->bl, SC_ENDURE, -1); + // 演奏/ダンスの中断 + 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 index befa690fd..1919007a0 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -1,186 +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
-
+// $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 index 8bc17003a..6026b1ebf 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -1,1651 +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;
-}
-
+// $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 index b4ccf5ccb..365a4490f 100644 --- a/src/map/pet.h +++ b/src/map/pet.h @@ -1,69 +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
-
+// $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 index e4b95f058..61f5fd920 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -1,6930 +1,6930 @@ -// $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]
-int buildin_getmapxy(struct script_state *st); //get map position for player/npc/pet/mob by Lorky [Lupus]
-
-
-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]
- {buildin_getmapxy,"getmapxy","siii*"}, //by Lorky [Lupus]
- {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_GUARDUP
- * 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;
-}
-
-/*==========================================
- * Get position for char/npc/pet/mob objects. Added by Lorky
- *
- * int getMapXY(MapName$,MaxX,MapY,type,[CharName$]);
- * where type:
- * MapName$ - String variable for output map name
- * MapX - Integer variable for output coord X
- * MapY - Integer variable for output coord Y
- * type - type of object
- * 0 - Character coord
- * 1 - NPC coord
- * 2 - Pet coord
- * 3 - Mob coord (not released)
- * CharName$ - Name object. If miss or "this" the current object
- *
- * Return:
- * 0 - success
- * -1 - some error, MapName$,MapX,MapY contains unknown value.
- *------------------------------------------
-*/
-int buildin_getmapxy(struct script_state *st){
- struct map_session_data *sd=NULL;
- struct npc_data *nd;
- struct pet_data *pd;
-
- int num;
- char *name;
- char prefix;
-
- int x,y,type;
- char *mapname;
-
- if( st->stack->stack_data[st->start+2].type!=C_NAME ){
- printf("script: buildin_getmapxy: not mapname variable\n");
- push_val(st->stack,C_INT,-1);
- return 0;
- }
- if( st->stack->stack_data[st->start+3].type!=C_NAME ){
- printf("script: buildin_getmapxy: not mapx variable\n");
- push_val(st->stack,C_INT,-1);
- return 0;
- }
- if( st->stack->stack_data[st->start+4].type!=C_NAME ){
- printf("script: buildin_getmapxy: not mapy variable\n");
- push_val(st->stack,C_INT,-1);
- return 0;
- }
-
-//??????????? >>> Possible needly check function parameters on C_STR,C_INT,C_INT <<< ???????????//
- type=conv_num(st,& (st->stack->stack_data[st->start+5]));
- mapname=calloc(24, 1);
-
- switch (type){
- case 0: //Get Character Position
- if( st->end>st->start+6 )
- sd=map_nick2sd(conv_str(st,& (st->stack->stack_data[st->start+6])));
- else
- sd=script_rid2sd(st);
-
- if ( sd==NULL ) { //wrong char name or char offline
- push_val(st->stack,C_INT,-1);
- return 0;
- }
-
-
- x=sd->bl.x;
- y=sd->bl.y;
- strncpy(mapname,sd->mapname,24);
- printf(">>>>%s %d %d\n",mapname,x,y);
- break;
- case 1: //Get NPC Position
- if( st->end > st->start+6 )
- nd=npc_name2id(conv_str(st,& (st->stack->stack_data[st->start+6])));
- else
- nd=(struct npc_data *)map_id2bl(st->oid);
-
- if ( nd==NULL ) { //wrong npc name or char offline
- push_val(st->stack,C_INT,-1);
- return 0;
- }
-
- x=nd->bl.x;
- y=nd->bl.y;
- strncpy(mapname,map[nd->bl.m].name,24);
- printf(">>>>%s %d %d\n",mapname,x,y);
- break;
- case 2: //Get Pet Position
- if( st->end>st->start+6 )
- sd=map_nick2sd(conv_str(st,& (st->stack->stack_data[st->start+6])));
- else
- sd=script_rid2sd(st);
-
- if ( sd==NULL ) { //wrong char name or char offline
- push_val(st->stack,C_INT,-1);
- return 0;
- }
-
- pd=sd->pd;
-
- if(pd==NULL){ //ped data not found
- push_val(st->stack,C_INT,-1);
- return 0;
- }
- x=pd->bl.x;
- y=pd->bl.y;
- strncpy(mapname,map[pd->bl.m].name,24);
-
- printf(">>>>%s %d %d\n",mapname,x,y);
- break;
-
- case 3: //Get Mob Position
- push_val(st->stack,C_INT,-1);
- return 0;
- default: //Wrong type parameter
- push_val(st->stack,C_INT,-1);
- return 0;
- }
-
- //Set MapName$
- num=st->stack->stack_data[st->start+2].u.num;
- name=(char *)(str_buf+str_data[num&0x00ffffff].str);
- prefix=*name;
-
- if( prefix!='$' )
- sd=script_rid2sd(st);
- else
- sd=NULL;
-
- set_reg(sd,num,name,(void*)mapname);
-
- //Set MapX
- num=st->stack->stack_data[st->start+3].u.num;
- name=(char *)(str_buf+str_data[num&0x00ffffff].str);
- prefix=*name;
-
- if( prefix!='$' )
- sd=script_rid2sd(st);
- else
- sd=NULL;
- set_reg(sd,num,name,(void*)x);
-
-
- //Set MapY
- num=st->stack->stack_data[st->start+4].u.num;
- name=(char *)(str_buf+str_data[num&0x00ffffff].str);
- prefix=*name;
-
- if( prefix!='$' )
- sd=script_rid2sd(st);
- else
- sd=NULL;
-
- set_reg(sd,num,name,(void*)y);
-
- //Return Success value
- push_val(st->stack,C_INT,0);
- 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;
-}
+// $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] +int buildin_getmapxy(struct script_state *st); //get map position for player/npc/pet/mob by Lorky [Lupus] + + +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] + {buildin_getmapxy,"getmapxy","siii*"}, //by Lorky [Lupus] + {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_GUARDUP + * 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; +} + +/*========================================== + * Get position for char/npc/pet/mob objects. Added by Lorky + * + * int getMapXY(MapName$,MaxX,MapY,type,[CharName$]); + * where type: + * MapName$ - String variable for output map name + * MapX - Integer variable for output coord X + * MapY - Integer variable for output coord Y + * type - type of object + * 0 - Character coord + * 1 - NPC coord + * 2 - Pet coord + * 3 - Mob coord (not released) + * CharName$ - Name object. If miss or "this" the current object + * + * Return: + * 0 - success + * -1 - some error, MapName$,MapX,MapY contains unknown value. + *------------------------------------------ +*/ +int buildin_getmapxy(struct script_state *st){ + struct map_session_data *sd=NULL; + struct npc_data *nd; + struct pet_data *pd; + + int num; + char *name; + char prefix; + + int x,y,type; + char *mapname; + + if( st->stack->stack_data[st->start+2].type!=C_NAME ){ + printf("script: buildin_getmapxy: not mapname variable\n"); + push_val(st->stack,C_INT,-1); + return 0; + } + if( st->stack->stack_data[st->start+3].type!=C_NAME ){ + printf("script: buildin_getmapxy: not mapx variable\n"); + push_val(st->stack,C_INT,-1); + return 0; + } + if( st->stack->stack_data[st->start+4].type!=C_NAME ){ + printf("script: buildin_getmapxy: not mapy variable\n"); + push_val(st->stack,C_INT,-1); + return 0; + } + +//??????????? >>> Possible needly check function parameters on C_STR,C_INT,C_INT <<< ???????????// + type=conv_num(st,& (st->stack->stack_data[st->start+5])); + mapname=calloc(24, 1); + + switch (type){ + case 0: //Get Character Position + if( st->end>st->start+6 ) + sd=map_nick2sd(conv_str(st,& (st->stack->stack_data[st->start+6]))); + else + sd=script_rid2sd(st); + + if ( sd==NULL ) { //wrong char name or char offline + push_val(st->stack,C_INT,-1); + return 0; + } + + + x=sd->bl.x; + y=sd->bl.y; + strncpy(mapname,sd->mapname,24); + printf(">>>>%s %d %d\n",mapname,x,y); + break; + case 1: //Get NPC Position + if( st->end > st->start+6 ) + nd=npc_name2id(conv_str(st,& (st->stack->stack_data[st->start+6]))); + else + nd=(struct npc_data *)map_id2bl(st->oid); + + if ( nd==NULL ) { //wrong npc name or char offline + push_val(st->stack,C_INT,-1); + return 0; + } + + x=nd->bl.x; + y=nd->bl.y; + strncpy(mapname,map[nd->bl.m].name,24); + printf(">>>>%s %d %d\n",mapname,x,y); + break; + case 2: //Get Pet Position + if( st->end>st->start+6 ) + sd=map_nick2sd(conv_str(st,& (st->stack->stack_data[st->start+6]))); + else + sd=script_rid2sd(st); + + if ( sd==NULL ) { //wrong char name or char offline + push_val(st->stack,C_INT,-1); + return 0; + } + + pd=sd->pd; + + if(pd==NULL){ //ped data not found + push_val(st->stack,C_INT,-1); + return 0; + } + x=pd->bl.x; + y=pd->bl.y; + strncpy(mapname,map[pd->bl.m].name,24); + + printf(">>>>%s %d %d\n",mapname,x,y); + break; + + case 3: //Get Mob Position + push_val(st->stack,C_INT,-1); + return 0; + default: //Wrong type parameter + push_val(st->stack,C_INT,-1); + return 0; + } + + //Set MapName$ + num=st->stack->stack_data[st->start+2].u.num; + name=(char *)(str_buf+str_data[num&0x00ffffff].str); + prefix=*name; + + if( prefix!='$' ) + sd=script_rid2sd(st); + else + sd=NULL; + + set_reg(sd,num,name,(void*)mapname); + + //Set MapX + num=st->stack->stack_data[st->start+3].u.num; + name=(char *)(str_buf+str_data[num&0x00ffffff].str); + prefix=*name; + + if( prefix!='$' ) + sd=script_rid2sd(st); + else + sd=NULL; + set_reg(sd,num,name,(void*)x); + + + //Set MapY + num=st->stack->stack_data[st->start+4].u.num; + name=(char *)(str_buf+str_data[num&0x00ffffff].str); + prefix=*name; + + if( prefix!='$' ) + sd=script_rid2sd(st); + else + sd=NULL; + + set_reg(sd,num,name,(void*)y); + + //Return Success value + push_val(st->stack,C_INT,0); + 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 index c0c4ba20f..b50c46693 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -1,39 +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
-
+// $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 index 2d6b799df..b1b0ed2fb 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -1,10805 +1,10805 @@ -// $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,SC_EDP,-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 && skillid==MG_FROSTDIVER)
- 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 < 20*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 < 7*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 < (10 + 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 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 < (skilllv*15) )
- 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 )
-{
-
- if(skilllv <= 0) return 0;
-
- 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(skilllv <= 0) return 0;
- 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 )
-{
- if(skilllv <= 0) return 0;
-
- struct map_session_data *sd=NULL;
- struct status_change *sc_data = battle_get_sc_data(src);
- 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);
- dir = dir < 4 ? dir+4 : dir-4; // change direction [Celest]
- if (bl->type == BL_PC)
- ((struct map_session_data *)bl)->dir=dir;
- else if (bl->type == BL_MOB)
- ((struct mob_data *)bl)->dir=dir;
- //skill_blown(src,bl,skill_get_blewcount(skillid,skilllv));
- }
- 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);
- if (skillid == SM_MAGNUM) // fire element for 10 seconds
- skill_status_change_start(src,SC_FLAMELAUNCHER,0,0,0,0,10000,0);
- }
- 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);
- map_foreachinarea(skill_attack_area,src->m,src->x-5,bl->y-5,bl->x+5,bl->y+5,0,BF_MAGIC,src,src,skillid,skilllv,tick,flag,BCT_ENEMY);
- 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;
- }
- if(sc_data) {
- if (sc_data[SC_MAGICPOWER].timer != -1 && skillid != HW_MAGICPOWER) //マジックパワ?の?果終了
- skill_status_change_end(src,SC_MAGICPOWER,-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 )
-{
- if(skilllv <= 0) return 0;
-
- 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: // moved - Celest
- 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 CG_MARIONETTE: /* マリオネットコントロ?ル */
- if(sd && dstsd){
- struct status_change *tsc_data = battle_get_sc_data(src);
- int sc = SkillStatusChangeTable[skillid];
- int sc2 = SC_MARIONETTE2;
-
- if((dstsd->bl.type!=BL_PC)
- || (sd->bl.id == dstsd->bl.id)
- || (!sd->status.party_id)
- || (sd->status.party_id != dstsd->status.party_id)) {
- clif_skill_fail(sd,skillid,0,0);
- map_freeblock_unlock();
- return 1;
- }
- if(tsc_data){
- if(tsc_data[sc].timer == -1) {
- skill_status_change_start (src,sc,skilllv,0,bl->id,0,skill_get_time(skillid,skilllv),0);
- skill_status_change_start (bl,sc2,skilllv,0,src->id,0,skill_get_time(skillid,skilllv),0);
- }
- else {
- skill_status_change_end(src, sc, -1);
- skill_status_change_end(bl, sc2, -1);
- }
- 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: /* メモライズ */
- case ASC_EDP: // [Celest]
- 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);
- 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 );
- if (bl->type == BL_MOB)
- mob_changestate((struct mob_data *)src,MS_DELAY,skill_time);
- else if (bl->type == BL_PC)
- sd->attackabletime = sd->canmove_tick = tick + 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){
- clif_skill_nodamage(src,bl,skillid,skilllv,1);
- if (md)
- mob_damage(NULL,md,md->hp,0);
- else if (sd)
- pc_damage(NULL,sd,sd->status.hp);
- }
- 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*10*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 ASC_CDP: // Temporary skill for Create Deadly Poison[Celest]
- 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 = 678;
- item_tmp.identify = 1;
- tbl.id = 0;
- 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 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)
-{
- if(skilllv <= 0) return 0;
-
- 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 ||
- sd->sc_data[SC_MARIONETTE].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;
- }
- }
-
- if(sd->skilllv <= 0) 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);
- if (((struct map_session_data *)src)->sc_data[SC_VIOLENTGALE].timer!=-1)
- limit *= 1.5;
- 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;
- if(skilllv < 6)
- range=1;
- else
- range=2;
- 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_SANDMAN: /* サンドマン */
- case HT_CLAYMORETRAP: /* クレイモア?トラップ */
- limit=skill_get_time(skillid,skilllv);
- range=2;
- break;
- case HT_SKIDTRAP: /* スキッドトラップ */
- case HT_LANDMINE: /* ランドマイン */
- case HT_ANKLESNARE: /* アンクルスネア */
- case PF_SPIDERWEB: /* スパイダ?ウェッブ */
- case HT_FLASHER: /* フラッシャ? */
- case HT_FREEZINGTRAP: /* フリ?ジングトラップ */
- case HT_BLASTMINE: /* ブラストマイン */
- 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);
- if (((struct map_session_data *)src)->sc_data[SC_DELUGE].timer!=-1)
- limit *= 2;
- 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);
- map_foreachinarea(skill_attack_area,bl->m,bl->x-1,bl->y-1,bl->x+1,bl->y+1,0,BF_MAGIC,ss,&src->bl,sg->skill_id,sg->skill_lv,tick,0,BCT_ENEMY); // area damage [Celest]
- 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:
- case 0xb6: /* フォグウォ?ル */
- {
- 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: /* フォグウォ?ル */ - moved [celest]
- //とりあえず何もしない
- 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);
- struct status_change *sc_data=battle_get_sc_data(bl);
- if( target==bl ) {
- skill_status_change_end(bl,SC_FOGWALL,-1);
- if (sc_data && sc_data[SC_BLIND].timer!=-1)
- sc_data[SC_BLIND].timer = add_timer(
- gettick() + 30000, skill_status_change_timer, bl->id, 0);
- }
- 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;
- }
- }
- }
-
- if(sd->skilllv <= 0) 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;
- if(skilllv <= 0) return 0;
- 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 ||
- (sd->sc_data[SC_MARIONETTE].timer != -1 && sd->skillid != CG_MARIONETTE)){
- clif_skill_fail(sd,sd->skillid,0,0);
- return 0; /* ?態異常や沈?など */
- }
- }
- skill = sd->skillid;
- lv = sd->skilllv;
- if(lv <= 0) return 0;
- 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: /* ファイア?ウォ?ル */
- case WZ_QUAGMIRE:
- case WZ_FIREPILLAR: // celest
- case PF_FOGWALL:
- /* ?制限 */
- 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 == WZ_FIREPILLAR && lv<=5)
- continue; // no gemstones for 1-5 [Celest]
- 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;
- }
-
- if(lv <= 0) return 0;
-
- 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 ||
- (sd->sc_data[SC_MARIONETTE].timer != -1 && sd->skillid != CG_MARIONETTE)){
- 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/2;
- 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); // moved
-
- 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 ||
- sd->sc_data[SC_MARIONETTE].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;
- if(skill_lv <= 0) return 0;
- 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(skilllv <= 0) return 0;
-
- 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);
- if(skilllv <= 0) return 0;
- 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)
-{
- if(skilllv <= 0) return 0;
- 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);
- if(skilllv <= 0) return 0;
- 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: /* メルトダウン */
- case SC_EDP: // Celest
- case SC_MARIONETTE:
- case SC_MARIONETTE2:
- 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;
- val2 = 7; // [Celest]
- 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_EDP: // [Celest]
- calc_flag = 1;
- break;
- case SC_POISONREACT: /* ポイズンリアクト */
- val2=val1/2 + val1%2; // [Celest]
- 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:
- calc_flag = 1;
- 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: /* マリオネットコントロ?ル */
- case SC_MARIONETTE2:
- calc_flag = 1;
- *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;
- case SC_FOGWALL:
- val2 = 75;
- // calc_flag = 1; // not sure of effects yet [celest]
- 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)
-{
- if(skilllv <= 0) return 0;
- 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;
-}
+// $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,SC_EDP,-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 && skillid==MG_FROSTDIVER) + 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 < 20*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 < 7*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 < (10 + 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 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 < (skilllv*15) ) + 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 ) +{ + + if(skilllv <= 0) return 0; + + 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(skilllv <= 0) return 0; + 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 ) +{ + if(skilllv <= 0) return 0; + + struct map_session_data *sd=NULL; + struct status_change *sc_data = battle_get_sc_data(src); + 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); + dir = dir < 4 ? dir+4 : dir-4; // change direction [Celest] + if (bl->type == BL_PC) + ((struct map_session_data *)bl)->dir=dir; + else if (bl->type == BL_MOB) + ((struct mob_data *)bl)->dir=dir; + //skill_blown(src,bl,skill_get_blewcount(skillid,skilllv)); + } + 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); + if (skillid == SM_MAGNUM) // fire element for 10 seconds + skill_status_change_start(src,SC_FLAMELAUNCHER,0,0,0,0,10000,0); + } + 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); + map_foreachinarea(skill_attack_area,src->m,src->x-5,bl->y-5,bl->x+5,bl->y+5,0,BF_MAGIC,src,src,skillid,skilllv,tick,flag,BCT_ENEMY); + 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; + } + if(sc_data) { + if (sc_data[SC_MAGICPOWER].timer != -1 && skillid != HW_MAGICPOWER) //マジックパワ?の?果終了 + skill_status_change_end(src,SC_MAGICPOWER,-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 ) +{ + if(skilllv <= 0) return 0; + + 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: // moved - Celest + 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 CG_MARIONETTE: /* マリオネットコントロ?ル */ + if(sd && dstsd){ + struct status_change *tsc_data = battle_get_sc_data(src); + int sc = SkillStatusChangeTable[skillid]; + int sc2 = SC_MARIONETTE2; + + if((dstsd->bl.type!=BL_PC) + || (sd->bl.id == dstsd->bl.id) + || (!sd->status.party_id) + || (sd->status.party_id != dstsd->status.party_id)) { + clif_skill_fail(sd,skillid,0,0); + map_freeblock_unlock(); + return 1; + } + if(tsc_data){ + if(tsc_data[sc].timer == -1) { + skill_status_change_start (src,sc,skilllv,0,bl->id,0,skill_get_time(skillid,skilllv),0); + skill_status_change_start (bl,sc2,skilllv,0,src->id,0,skill_get_time(skillid,skilllv),0); + } + else { + skill_status_change_end(src, sc, -1); + skill_status_change_end(bl, sc2, -1); + } + 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: /* メモライズ */ + case ASC_EDP: // [Celest] + 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); + 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 ); + if (bl->type == BL_MOB) + mob_changestate((struct mob_data *)src,MS_DELAY,skill_time); + else if (bl->type == BL_PC) + sd->attackabletime = sd->canmove_tick = tick + 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){ + clif_skill_nodamage(src,bl,skillid,skilllv,1); + if (md) + mob_damage(NULL,md,md->hp,0); + else if (sd) + pc_damage(NULL,sd,sd->status.hp); + } + 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*10*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 ASC_CDP: // Temporary skill for Create Deadly Poison[Celest] + 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 = 678; + item_tmp.identify = 1; + tbl.id = 0; + 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 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) +{ + if(skilllv <= 0) return 0; + + 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 || + sd->sc_data[SC_MARIONETTE].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; + } + } + + if(sd->skilllv <= 0) 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); + if (((struct map_session_data *)src)->sc_data[SC_VIOLENTGALE].timer!=-1) + limit *= 1.5; + 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; + if(skilllv < 6) + range=1; + else + range=2; + 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_SANDMAN: /* サンドマン */ + case HT_CLAYMORETRAP: /* クレイモア?トラップ */ + limit=skill_get_time(skillid,skilllv); + range=2; + break; + case HT_SKIDTRAP: /* スキッドトラップ */ + case HT_LANDMINE: /* ランドマイン */ + case HT_ANKLESNARE: /* アンクルスネア */ + case PF_SPIDERWEB: /* スパイダ?ウェッブ */ + case HT_FLASHER: /* フラッシャ? */ + case HT_FREEZINGTRAP: /* フリ?ジングトラップ */ + case HT_BLASTMINE: /* ブラストマイン */ + 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); + if (((struct map_session_data *)src)->sc_data[SC_DELUGE].timer!=-1) + limit *= 2; + 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); + map_foreachinarea(skill_attack_area,bl->m,bl->x-1,bl->y-1,bl->x+1,bl->y+1,0,BF_MAGIC,ss,&src->bl,sg->skill_id,sg->skill_lv,tick,0,BCT_ENEMY); // area damage [Celest] + 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: + case 0xb6: /* フォグウォ?ル */ + { + 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: /* フォグウォ?ル */ - moved [celest] + //とりあえず何もしない + 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); + struct status_change *sc_data=battle_get_sc_data(bl); + if( target==bl ) { + skill_status_change_end(bl,SC_FOGWALL,-1); + if (sc_data && sc_data[SC_BLIND].timer!=-1) + sc_data[SC_BLIND].timer = add_timer( + gettick() + 30000, skill_status_change_timer, bl->id, 0); + } + 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; + } + } + } + + if(sd->skilllv <= 0) 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; + if(skilllv <= 0) return 0; + 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 || + (sd->sc_data[SC_MARIONETTE].timer != -1 && sd->skillid != CG_MARIONETTE)){ + clif_skill_fail(sd,sd->skillid,0,0); + return 0; /* ?態異常や沈?など */ + } + } + skill = sd->skillid; + lv = sd->skilllv; + if(lv <= 0) return 0; + 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: /* ファイア?ウォ?ル */ + case WZ_QUAGMIRE: + case WZ_FIREPILLAR: // celest + case PF_FOGWALL: + /* ?制限 */ + 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 == WZ_FIREPILLAR && lv<=5) + continue; // no gemstones for 1-5 [Celest] + 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; + } + + if(lv <= 0) return 0; + + 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 || + (sd->sc_data[SC_MARIONETTE].timer != -1 && sd->skillid != CG_MARIONETTE)){ + 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/2; + 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); // moved + + 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 || + sd->sc_data[SC_MARIONETTE].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; + if(skill_lv <= 0) return 0; + 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(skilllv <= 0) return 0; + + 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); + if(skilllv <= 0) return 0; + 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) +{ + if(skilllv <= 0) return 0; + 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); + if(skilllv <= 0) return 0; + 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: /* メルトダウン */ + case SC_EDP: // Celest + case SC_MARIONETTE: + case SC_MARIONETTE2: + 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; + val2 = 7; // [Celest] + 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_EDP: // [Celest] + calc_flag = 1; + break; + case SC_POISONREACT: /* ポイズンリアクト */ + val2=val1/2 + val1%2; // [Celest] + 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: + calc_flag = 1; + 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: /* マリオネットコントロ?ル */ + case SC_MARIONETTE2: + calc_flag = 1; + *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; + case SC_FOGWALL: + val2 = 75; + // calc_flag = 1; // not sure of effects yet [celest] + 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) +{ + if(skilllv <= 0) return 0; + 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 index 310a93f21..c82a0c932 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -1,857 +1,857 @@ -// $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,
-
- SC_EDP = 114, // [Celest]
- SC_MARIONETTE2 = 122,
- SC_BLEEDING = 124,
-
-// -- 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_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
-
+// $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, + + SC_EDP = 114, // [Celest] + SC_MARIONETTE2 = 122, + SC_BLEEDING = 124, + +// -- 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_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 index b10b73bb0..fc6f63cdd 100644 --- a/src/map/storage.c +++ b/src/map/storage.c @@ -1,595 +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;
-}
+// $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 index 4e89e657a..352dee4f0 100644 --- a/src/map/storage.h +++ b/src/map/storage.h @@ -1,39 +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
+// $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 index 41a89cd7a..babcdc6e0 100644 --- a/src/map/trade.c +++ b/src/map/trade.c @@ -1,286 +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);
- }
- }
- }
-}
+#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 index d796df8e6..01cbce7eb 100644 --- a/src/map/trade.h +++ b/src/map/trade.h @@ -1,13 +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_
+// $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 index 703b1b9b9..0bf0b884e 100644 --- a/src/map/vending.c +++ b/src/map/vending.c @@ -1,170 +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;
- }
-}
-
+// $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 index e5b958386..41aa731bb 100644 --- a/src/map/vending.h +++ b/src/map/vending.h @@ -1,12 +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_
+// $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_ |