Parcourir la source

* Updated core and map-server to jA 1115~1137
* Fixed a typo in Volcano

git-svn-id: https://svn.code.sf.net/p/rathena/svn/branches/stable@1206 54d463be-8e91-2dee-dedb-b68131a5f0ec

celest il y a 20 ans
Parent
commit
055dde5bb4

+ 18 - 0
Changelog-SVN.txt

@@ -1,6 +1,24 @@
 Date	Added
 
 03/07
+        * Updated core and map-server to jA 1115~1137 [celest]
+          - Added monster_delay_damage to battle conf
+          - Increased some default settings in script conf
+          - Updated Brandish Spear, Soul Change, Soul Burn
+          - Updated Body Relocation (shorter distance)
+          - Added monster skill NPC_EXPLOSIONSPIRITS
+          - Corrected Mindbreaker level to 5
+          - Updated Meteor Assault to instant-cast
+          - Removed some unused code for Breaker
+          - Temporarily set Emperium to be immune to Breaker
+          - Added command @users - shows the percentage of users in all maps
+          - Don't save status if the player is set for disconnection
+          - Added free block lock-checking system
+          - Added saving the processes' ID into [xx-server.pid]
+          - Fixed a memory leak with duplicate script labels
+          + For more detailed logs check 'Readme-jap'
+
+        * Fixed a typo in Volcano, thanks to Ilpalazzo-sama [celest]
         * Fixed Apple of Idun reading the wrong skill level and giving too much HP
           [celest]
 

+ 428 - 0
Readme-jap

@@ -1,3 +1,431 @@
+--------------------
+//1136 by by eigen
+
+・1135で消えていたbattle_athena.confの項目とデフォルト値を復活
+・conf_ref.txtにnext_exp_limitの説明を追加
+
+	(conf)
+		battle_athena.conf	- 消えた項目とデフォルト値を復活
+	(doc)
+		conf_ref.txt		- next_exp_limitの説明を追加
+
+--------------------
+//1135 by by Toshi^2
+・パッチ1125で修正された、経験値の上限設定を従来方式の制限無しも選べるように変更
+
+	(db)
+		battle_athena.conf	- next_exp_limitを追加。
+	(src/map)
+		battle.c	- battle_config_read() 修正
+		battle.h	- struct Battle_Config{}に int next_exp_limit; を追加。
+		pc.c		- pc_gainexp() 修正
+
+--------------------
+//1134 by End_of_exam
+
+・1132で#undef closeを忘れていたバグを修正(socket.c)
+・1133のアイテムdupe対策が不完全だったのを修正(map.c)
+・athena-start stop , kill の順番をmap -> char -> login に変更
+    (athena-start thanks to eigenさん)
+
+	(/)
+		athena-start	- athena-start stop , kill の順番修正
+
+	(src/common)
+		socket.c		- #undef close 追加
+
+	(src/map)
+		map.c			- map_quit() 修正
+
+--------------------
+//1133 by End_of_exam
+
+・mapflag nosave が指定されたマップで死んでリスタートする時に、セーブポイントが
+ 別マップサーバーにあると、(nul,0,0)に飛ばされていたバグを修正(pc.c)
+・マップサーバーを分配している時に、細工をした特殊なツールを使うことによって、
+ アイテムがdupeできたバグを修正。(pc.c)
+・buildin_menu, buildin_select() がバッファオーバーフローを起こしていた
+ バグを修正(script.c)
+
+	(src/map)
+		pc.c			- pc_makesavestatus(), pc_setpos(), pc_autosave_sub() 修正
+		script.c		- buildin_menu(), buildin_select() 修正
+
+--------------------
+//1132 by End_of_exam
+・@users コマンド(サーバー内の人数マップを表示)を追加(atcommand.c / h)
+・guild_check_alliance() を呼び出すときのチェックを追加(mob.c battle.c)
+・マップサーバー分配時にギルドのメンバーが抜けた時、そのギルドメンバーが
+ 一人もログインしていないマップサーバーが落ちていたのを修正(guild.c)
+・1130で見切りの回避率上昇が消えていたのを戻す(status.c)
+・pid 対応版のstart, athena-start を統合(start , athena_start)
+・田代砲対策、Shinomoriさんの do_sendrecv() 高速化を組み込む
+ (socket.c socket.conf Makefile)
+・socket の高速化
+  1. FIFOFLUSH が実行される頻度を下げる(socket.c char.c)
+  2. 不正なfdを0 に変更(socket.c socket.h chrif.c char.c)
+
+	(/)
+		start			- pid ファイルに対応するように修正
+		sthena-start	- pid ファイルに対応するように修正
+		Makefile		- "-D_XOPEN_SOURCE -D_BSD_SOURCE" 追加
+
+	(conf/)
+		help.txt		- @users 追加、@mes の修正
+		socket.conf		- アクセス制限の設定ファイル
+
+	(src/common/)
+		socket.c		- アクセス制限の追加、色々高速化
+		socket.h		- FIFO命令の高速化
+
+	(src/char/)
+		char.c			- parse_tologin(), parse_char() 更新
+
+	(src/map/)
+		atcommand.c		- @users 追加
+		atcommand.h		- @users 追加
+		battle.c		- battle_calc_damage() 修正
+		chrif.c			- 不正なfdを0 に変更したのに伴う修正
+		guild.c			- guild_member_leaved() 修正
+		mob.c			- mob_gvmobcheck() 修正
+		status.c		- status_calc_pc() 修正
+
+--------------------
+//1131 by eigen
+・ギルド拡張の人数増分を+2/Lvから+4/Lvに変更
+・メテオストームにスタンがかかるよう修正
+・ロードオブヴァーミリオンに暗闇がかかるよう修正
+・ヒルトバインディングを取っていればSTR+1 ATK+4が付くよう変更
+・ヒルトバインディングを取っていればAR・OT・WPがの効果時間が10%長くなるよう変更
+・AR・OTのパーティーメンバー効果時間減少を撤廃
+・フロストダイバーで凍結する際、凍結時間がMDEFに影響されるよう変更
+・skill_db.txt、skill_require_db.txt、skill_cast_db.txtをOWNや各職Wikiなどを参考に修正
+
+	(src/map)
+		skill.c
+		status.c
+	(db)
+		skill_db.txt
+		skill_cast_db.txt
+		skill_require_db.txt
+
+--------------------
+//1130 by eigen
+・所持限界量増加の+100/Lvを+200/Lvに修正
+・シーフの上位職に於いて回避率増加のFlee上昇率+3/Lvを+4/Lvに修正
+・アサシン系が回避率増加を取得している場合、移動速度が+0.5%/Lvになるよう修正
+・プレッシャーのSP攻撃を実装
+・プリザーブ、フルストリップ、武器精錬、スリムピッチャー、フルケミカルチャージ
+をdbに追加
+
+	(src/map)
+		skill.c			- skill_additional_effect() 修正
+		status.c		- status_calc_pc() 修正
+	(db)
+		skill_db.txt
+		skill_cast_db.txt
+		skill_require_db.txt
+		skill_tree.txt
+
+--------------------
+//1129 by En_of_exam
+
+・NPC イベントが重複した場合のメモリ解放手順が違っていたバグを修正
+  (npc.c thanks to TOSHI^2さん)
+
+	(src/map)
+		npc.c		- npc_parse_script() 修正
+
+--------------------
+//1128 by 悩める人
+・アイテムを消費せずに使用するかのオプション追加
+・カード、装備品、エル・オリのドロップ率を別に設定出来るようにオプション追加
+・battle_athena.confの初期設定で矢・聖水等を作成時に名前を付けないように変更
+ (本鯖ではまだ来てないと思ったので初期設定を変えました)
+	(src/map)
+		battle.c
+		mob.c
+		pc.c
+		battle.h
+	(conf)
+		battle_athena.conf
+
+--------------------
+//1127 by End_of_exam
+
+・getarraysize() が正しい値を返さないバグを修正(script.c)
+ このバグの影響で、deletearray() 命令の動作が正常なものと異なっていました。
+
+・buildin_deletearray() の最適化(script.c)
+・シグナル処理中に再度シグナルが呼ばれる可能性に対処する(core.c)
+・委託販売を追加してみる(npc_test_seller.txt)
+
+	(src/map)
+		script.c	- getarraysize() , buildin_deletearray() 修正
+
+	(src/common)
+		core.c		- sig_proc() 修正
+
+	(script/sample)
+		npc_test_seller.txt		- 委託販売NPC
+
+--------------------
+//1126 by eigen
+・メモライズの効果回数と詠唱短縮比率をそれぞれ5回、1/2に修正
+
+	(src/map)
+		skill.c		- 1/3になっているのを1/2に修正
+		status.c	- 3回になっているのを5回に修正
+
+--------------------
+//1125 by lizorett
+・ブランディッシュスピアのノックバックを3セルにし、ミス時にはノックバックしない
+よう変更
+・スピアスタブを対象から自分に向かって4マスの範囲攻撃に変更(本鯖仕様)
+・鷹/投石をニュマで防げるよう変更
+・ボウリングバッシュが対象にミスした場合にはノックバックしないよう変更
+・ソウルブレイカーのダメージ計算、ニュマでミスになるよう変更
+・獲得経験値の上限(現レベルの必要経験値-1)を設定
+・バジリカ展開時に展開者はノックバックしないよう変更
+・メテオアサルトを即時発動、使用者中心、詠唱500ms固定、エフェクト有に変更
+・ストリップウェポン時のmobの攻撃力低下を10%に変更
+・掛けられているものより低レベルのブレスにより呪い/石化が解除できるよう変更
+・ソウルバーン/マインドブレーカー/ソウルチェンジ実装
+・シャープシューティングを射線にいる敵にもダメージを与えるよう変更、クリティカル
+確率+20%で防御無視ダメージに変更
+・投石など一部のスキルが草などに1ダメージにならない問題を修正
+
+	(db)
+		skill_db.txt- BDS/メテオアサルト変更、スキル追加
+		skill_cast_db.txt
+					- スキル追加
+		skill_require_db.txt
+					- スキル追加
+	(src/map)
+		battle.c	- ソウルブレイカーのダメージ計算を変更
+					- シャープシューティングのクリティカル確率修正
+					- 鷹/投石をニュマで防げるよう変更
+		skill.h		- SC_MINDBREAKER追加
+		skill.c		- BDS/BBのノックバックを修正
+					- スピアスタブを範囲攻撃に変更
+					- メテオアサルト修正
+					- ソウルバーン/マインドブレーカー/ソウルチェンジ実装
+		path.c		- シャープシューティングの射線計算を追加
+		pc.c		- 獲得経験値の上限(前のレベルの経験値-1)を設定
+		status.c	- マインドブレーカーのmatk上昇/mdef減少の実装
+		map.h		- シャープシューティングの射線計算用構造体を追加
+
+--------------------
+//1124 by もっさり
+敵が使う爆裂波動実装
+効果
+atk1,atk2 1000*skilllv加算
+hit 20*skilllv加算
+
+	(src/map)
+		skill.c
+		skill.h 	NPC_EXPLOSIONSPIRITS関係を追加
+		status.c    
+	(db)
+		skill_db.txt
+		skill_cast_db.txt	
+
+		
+
+--------------------
+//1123 by Nameless
+・Athenaサービス化キットを追加しました。(NT/2000/XP/2003/LH)
+ 詳しい方法はdoc内のinstasv.txtを参照してください
+
+	(bin/tool)
+		instasv.bat	- サービス登録用バッチ
+		delasv.bat	- サービス抹消用バッチ
+	(doc/)
+		instasv.txt	- 説明書(テキスト版)
+
+--------------------
+//1122 by End_of_exam
+
+・1120のstrdb のキーを保存し忘れていたバグ修正(db.c)
+・念のため1121、1120のreadme をマージして、両方に含まれていたファイルを添付する
+
+	(src/char)
+		char.c		- 1121のものを添付
+
+	(src/common)
+		mmo.h		- 1121のものを添付
+		db.h		- 1120のものを添付
+		db.c		- strdb のキーを保存するようにする
+
+	(src/map)
+		battle.c	- 1121のものを添付
+		guild.c		- 1121のものを添付
+		guild.h		- 1121のものを添付
+		mob.c		- 1121のものを添付
+		skill.c		- 1121のものを添付
+		skill.h		- 1121のものを添付
+
+--------------------
+//1121 by _
+
+・ロードナイト/パラディンのログイン時のエラー対策
+・Gvでの同盟の扱いを修正
+ エンペリウム攻撃不可、ガーディアンから攻撃されないように修正
+・新追加スキル用の定数追加修正
+
+	(src/char)
+		char.c
+			修正	mmo_char_send006b()
+	(src/common)
+		mmo.h
+			修正	MAX_SKILL=500
+			追加	新ギルドスキル(コメントアウトしてます)
+	(src/map)
+		battle.c
+			修正	battle_calc_damage()
+		guild.c
+		guild.h
+			追加	guild_check_alliance()
+		mob.c
+			修正	mob_gvmobcheck()
+		skill.c
+			修正	SkillStatusChangeTable[] (420-490)
+		skill.h
+			修正	MAX_SKILL_DB=500
+			追加	475以降の新スキルID
+
+--------------------
+//1120 by End_of_exam
+
+・db_foreach()の呼び出し先でdb_erase()が呼び出されているされている場合、
+ 複数回同じキーで関数を呼び出す可能性があるバグを修正(db.h db.c)
+
+ cygwin上で2重freeをした場合、プログラムが暴走する可能性があります。
+ char鯖との接続が切れたmap 鯖が暴走するバグは、これに起因しています。
+
+	(src/common)
+		db.c		- db_eraseを一時的にロックする機能追加
+		db.h		- db_eraseを一時的にロックする機能追加
+
+--------------------
+//1119 by ICO
+
+・NPCスキル(ブレイクウェポン、ブレイクアーマー、ブレイクヘルム、ブレイクシールド)の実装
+・battle_athena.confにmonster_damage_delayを追加。
+ noを指定するとFW等のノックバックスキルの挙動が多少本鯖に近づくかも…?
+
+	(db)
+		skill_db.txt
+		skill_cast_db.txt
+	(conf/)
+		battle_athena.conf
+			monster_damage_delay 追加
+	(map/)
+		battle.c
+		battle.h
+		mob.c
+			monster_damage_delay関連を追加
+		skill.c
+		skill.h
+			skill_additional_effect,skill_castend_damage_id 修正
+
+--------------------
+//1118 by BDPQ銀 [ 2005/02/10 ]
+■データベースが変更されています。導入時には御注意ください■
+・スキルの固定詠唱時間を skill_cast_db.txt に移動。
+  詠唱時間の計算は、 (通常詠唱 + 固定詠唱)*メモライズ補正 となります。
+  skill_cast_dbの書式は
+    [ID],[cast_list(通常詠唱)],[fixed_cast_list(固定詠唱)],[delay_list(ディレイ)],[upkeep_time(維持時間)],[upkeep_time2(維持時間2)] です。
+・アブラカタブラをディレイにASPDによるディレイを付加しないよう修正(即発動スキル用)
+・新2次職のskill_cast_dbに関する項目の修正
+
+	(src/map)
+		skill.c			-	skill_use_id()			修正	(詠唱時間計算部 ・ メモライズ/魔法力増幅 固定詠唱時間部削除)
+															(アブラカタブラの修正)
+							skill_use_pos()			修正	(詠唱時間計算部)
+							skill_readdb()			修正	(cast_db 読込部)
+		skill.h			-	skill_db				修正	(fixedcastの追加)
+							skill_get_fixedcast()	追加	(dbから固定詠唱時間の取得)
+
+	(db)
+		skill_cast_db.txt-	fixed_cast_list			追加	(固定詠唱時間) 
+															魔法力増幅-700、メモライズ-5000に設定
+
+							361(アスムプティオ)		修正	( R.O.M 776を参考に詠唱/ディレイを修正 )
+							365(マジッククラッシャー)修正	( R.O.M 776を参考に詠唱/ディレイを追加 )
+							373(ライフ置き換え)		修正	( R.O.M 776を参考にディレイを修正 )
+							375(ソウルバーン)		追加	( R.O.M 776を参考にディレイを追加 ) ( スキル効果は実装していません )
+							381(ファルコンアサルト)	修正	( R.O.M 776を参考にディレイを修正 )
+							383(ウィンドウォーク)	修正	( R.O.M 776を参考に詠唱/ディレイ/効果時間を修正 )	
+							384(メルトダウン)		修正	( R.O.M 776を参考に詠唱/ディレイを修正 )	
+							387(カートブースト)		修正	( R.O.M 776を参考に効果時間を修正 )	
+							398(ヘッドクラッシュ)	修正	( R.O.M 776を参考にディレイ持続時間を修正 )
+							406(メテオアサルト)		修正	( R.O.M 776を参考に詠唱/ディレイを追加 )
+
+	(doc)
+		db_ref.txt		-	1. db/skill_cast_db.txt	修正	(fixed_cast_listの項目を追加)
+
+--------------------
+//1117 by End_of_exam
+
+・ベナムスプラッシャーを毒状態の敵に使用したが、失敗した時(敵モンスターの
+ HPが2/3 以上だった時)に深刻なメモリリークが起きていたバグを修正(skill.c)
+・あなたに逢いたいが失敗した時に深刻なメモリリークが起きていたバグを修正(skill.c)
+
+ 上2つは、共にmap_freeblock_unlock() が抜けている為に発生していました。
+ ドロップアイテム、スキルユニット、取り巻きなどで確保されたメモリが、
+ 以降全く開放されなくなるというかなり深刻なメモリリークのバグです。
+ map_freeblock_lock() を呼ぶルーチンを修正する場合、ルーチンを抜けるときに、
+ map_freeblock_unlock() が呼ばれるように気を付けてください(return に注意!)。
+
+・map_freeblock_unlock() を忘れても良いように、定期的にblock_free_lockを
+ クリアするように修正(map.c)
+・Debian好き さんのMPVモンスターのHP計算がオーバーフローするバグ修正の取り込み(status.c)
+
+	(src/map)
+		skill.c		- skill_castend_nodamage_id() 修正
+		map.c		- map_freeblock_timer() 追加、 do_init() 修正
+		status.c	- status_get_max_hp() 修正
+
+--------------------
+//1116 by End_of_exam
+
+・copyarray で同じ配列を指定した時、コピー先の要素番号がコピー元の要素番号より
+ 大きい時の動作が不定になっていたバグを修正(script.c npc_test_array.txt)
+・関数宣言せずに関数定義したユーザー定義関数を呼び出そうとすると、エラーが出る
+ バグを修正(script.c)
+・スクリプトのオーバーフロー判定基準を緩和させる(script.c)
+・ギルドの告知に\nが使えるバグを修正(int_guild.c)
+・イベントdbのメモリリーク修正が不完全だったのを修正(npc.c)
+・db_foreachのチェック方法を変更(db.c)
+・起動時に*.pid (プロセスIDのファイル)を作成するようにする(core.c)
+・経験値所得が全体発言になっているバグを修正(clif.c)
+・叫ぶを全体発言に変更(clif.c)
+・testerさん作成のVC++ Toolkit2003 用のバッチファイルを同伴(vc07_make.bat)
+
+	(/)
+		vc07_make.bat	- testerさん作成のバッチファイルを同伴
+
+	(src/common)
+		db.c			- db_foreach() 修正
+		core.c			- main() 修正 , pid_create() , pid_delete() 追加
+
+	(src/char)
+		int_guild.c		- mapif_parse_GuildPosition() 修正
+
+	(src/map)
+		clif.c			- clif_disp_onlyself() , clif_onlymessage() 修正
+		npc.c			- npc_parse_script() 修正
+		script.c		- buildin_copyarray() , parse_syntax() 修正
+
+	(script/sample)
+		npc_test_array.txt	- チェック項目の追加
+
+--------------------
+//1115 by いど
+
+・サーバースナップショット
+
 --------------------
 //1114-fix1 by 稀枝
 

+ 7 - 4
conf-tmpl/battle_athena.conf

@@ -240,6 +240,9 @@ potion_produce_rate: 100
 // Allow monsters to be aggresive and attack first? (Note 1)
 monster_active_enable: yes
 
+// If a monster is attacked, will they have a delay in being able to move? (Note 1)
+monster_damage_delay: yes
+
 // Monster damage delay rate (Note 1)
 monster_damage_delay_rate: 100
 
@@ -552,16 +555,16 @@ party_skill_penalty: yes
 monster_class_change_full_recover: no
 
 // Do produced items have the maker's name on them? (Note 1)
-produce_item_name_input: yes
+produce_item_name_input: no
 
 // Do produced potions have the maker's name on them? (Note 1)
-produce_potion_name_input: yes
+produce_potion_name_input: no
 
 // Do crafted arrows have the maker's name on them? (Note 1)
-making_arrow_name_input: yes
+making_arrow_name_input: no
 
 // Does created holy water have the maker's name on it? (Note 1)
-holywater_name_input: yes
+holywater_name_input: no
 
 // Stop logout for 10 seconds after a hit? (Note 1)
 prevent_logout: yes

+ 19 - 2
conf-tmpl/script_athena.conf

@@ -1,3 +1,20 @@
+//      ______  __    __                                 
+//     /\  _  \/\ \__/\ \                                
+//   __\ \ \L\ \ \ ,_\ \ \___      __    ___      __     
+// /'__`\ \  __ \ \ \/\ \  _ `\  /'__`\/' _ `\  /'__`\   
+///\  __/\ \ \/\ \ \ \_\ \ \ \ \/\  __//\ \/\ \/\ \L\.\_ 
+//\ \____\\ \_\ \_\ \__\\ \_\ \_\ \____\ \_\ \_\ \__/.\_\
+// \/____/ \/_/\/_/\/__/ \/_/\/_/\/____/\/_/\/_/\/__/\/_/
+//  _   _   _   _   _   _   _     _   _   _   _   _   _
+// / \ / \ / \ / \ / \ / \ / \   / \ / \ / \ / \ / \ / \ 
+//( e | n | g | l | i | s | h ) ( A | t | h | e | n | a )
+// \_/ \_/ \_/ \_/ \_/ \_/ \_/   \_/ \_/ \_/ \_/ \_/ \_/
+//
+//--------------------------------------------------------
+// eAthena Script Configuration File
+//--------------------------------------------------------
+
+
 // When choosing those which it refines setting the letter which is indicated. (Those for word use other than Japanese?)
 refine_posword: Head,Body,Left hand,Right hand,Robe,Shoes,Accessory 1,Accessory 2,Head 2,Head 3,Not Equipped
 
@@ -9,9 +26,9 @@ warn_func_mismatch_paramnum: yes
 
 warn_cmd_mismatch_paramnum: yes
 
-check_cmdcount: 8192
+check_cmdcount: 65536
 
-check_gotocount: 512
+check_gotocount: 2048
 
 
 //---- Custom script functions ----

+ 11 - 11
db/skill_db.txt

@@ -56,7 +56,7 @@
 54,8,6,16,6,1,4,1,yes,0,0,0,magic,0	//ALL_RESURRECTION#リザレクション#
 55,0,0,0,0,0,10,0,no,0,0,0,weapon,0	//KN_SPEARMASTERY#槍修練#
 56,-1,8,1,0,0,10,3,no,0,0,0,weapon,0	//KN_PIERCE#ピア?ス#
-57,1,6,1,0,1,10,1,no,33,0,0,weapon,1	//KN_BRANDISHSPEAR#ブランディッシュスピア#
+57,1,6,1,0,1,10,1,no,33,0,0,weapon,3	//KN_BRANDISHSPEAR#ブランディッシュスピア#
 58,4,6,1,0,2,10,1,no,0,0,0,weapon,6	//KN_SPEARSTAB#スピアス?ブ#
 59,-3:-5:-7:-9:-11,6,1,0,0,5,1,no,0,0,0,weapon,0	//KN_SPEARBOOMERANG#スピアブ?メラン#
 60,0,6,4,0,1,10,1,no,0,0,0,weapon,0	//KN_TWOHANDQUICKEN#ツ?ハンドクイッケン#
@@ -313,7 +313,7 @@
 261,0,6,4,0,1,5,1,no,0,0,0,weapon,0	//MO_CALLSPIRITS#気功#
 262,6,6,16,0,1,1,1,no,0,0,0,weapon,0	//MO_ABSORBSPIRITS#気奪#
 263,0,8,0,0,0,10,3,no,0,0,0,weapon,0	//MO_TRIPLEATTACK#三段掌#
-264,50,6,2,0,1,1,1,no,0,0,0,none,0	//MO_BODYRELOCATION#残影#
+264,14,6,2,0,1,1,1,no,0,0,0,none,0	//MO_BODYRELOCATION#残影#
 265,0,0,0,0,0,10,0,no,0,0,0,weapon,0	//MO_DODGE#見切り#
 266,8,6,1,0,0,5,1,no,0,0,0,weapon,0	//MO_INVESTIGATE#発勁#
 267,10,8,1,0,0,5,1:2:3:4:5,no,0,0,0,weapon,0	//MO_FINGEROFFENSIVE#指弾#
@@ -392,10 +392,10 @@
 340,8,8,1,7,0,10,1:1:2:2:3:3:4:4:5:5,yes,0,2,0,magic,0	//NPC_DARKSOULSTRIKE#闇ソウルストライク#
 341,8,8,1,7,0,10,3:4:5:6:7:8:9:10:11:12,yes,0,2,0,magic,2:3:3:4:4:5:5:6:6:7	//NPC_DARKJUPITEL#闇ユピテル#
 
-343,1,6,1,0,1,10,1,yes,0,2,0,weapon,0	//NPC_BREAKWEAPON
-344,1,6,1,0,1,10,1,yes,0,2,0,weapon,0	//NPC_BREAKARMOR
-345,1,6,1,0,1,10,1,yes,0,2,0,weapon,0	//NPC_BREAKHELM
-346,1,6,1,0,1,10,1,yes,0,2,0,weapon,0	//NPC_BREAKSHIELD
+343,8,6,1,0,0,5,1,no,0,2,0,weapon,0	//NPC_BREAKWEAPON#ブレイクウェポン#
+344,8,6,1,0,0,5,1,no,0,2,0,weapon,0	//NPC_BREAKARMOR#ブレイクアーマー#
+345,8,6,1,0,0,5,1,no,0,2,0,weapon,0	//NPC_BREAKHELM#ブレイクヘルム#
+346,8,6,1,0,0,5,1,no,0,2,0,weapon,0	//NPC_BREAKSIELD#ブレイクシールド#
 347,-1,6,1,9,0,10,1,no,0,2,0,weapon,0	//NPC_UNDEADATTACK
 
 //342束縛
@@ -405,7 +405,7 @@
 //346盾壊し
 //347不死属性攻撃
 //348攻撃系エフェクト(後退?)
-//349赤爆裂
+349,0,6,4,0,1,5,0,no,0,0,0,weapon,0	//NPC_EXPLOSIONSPIRITS#NPC爆裂波動#
 //350速度増加エフェクト
 //351攻撃系スキルエフェクト
 //352攻撃系スキルエフェクト
@@ -431,8 +431,8 @@
 371,-2,8,4,0,0,5,1,no,0,0,0,weapon,0	//CH_TIGERFIST#伏虎拳#
 372,-2,8,4,0,0,10,1:1:2:2:3:3:4:4:5:5,no,0,0,0,weapon,0	//CH_CHAINCRUSH#連柱崩撃#
 373,0,6,4,0,1,5,1,no,0,0,0,magic,0	//PF_HPCONVERSION#ライフ置き換え#
-374,4,6,16,0,1,1,1,yes,0,0,0,magic,0	//PF_SOULCHANGE#?ウル?ェンジ#
-375,4,6,1,0,0,5,1,yes,0,0,0,magic,0	//PF_SOULBURN#?ウルバ?ン#
+374,8,6,16,0,1,1,1,yes,0,0,0,none,0	//PF_SOULCHANGE#?ウル?ェンジ#
+375,8,6,1,0,0,5,1,yes,0,0,0,magic,0	//PF_SOULBURN#?ウルバ?ン#
 376,0,0,0,0,1,5,1,no,0,0,0,weapon,0	//ASC_KATAR#アドバンスドカ??ル研究#
 377,0,0,4,0,1,10,1,no,0,0,0,misc,0	//ASC_HALLUCINATION#ハルシネ?ションウォ?ク#
 378,0,6,4,5,1,5,1,no,0,1024,0,weapon,0	//ASC_EDP#エン?ャントデッドリ??イズン#
@@ -459,11 +459,11 @@
 399,4,6,1,0,0,10,1,no,0,0,0,weapon,0	//LK_JOINTBEAT#ジョイントビ?ト#
 400,8,8,1,8,0,5,1:2:3:4:5,yes,0,0,0,magic,0	//HW_NAPALMVULCAN#ナパ??バルカン#
 401,0,6,4,0,1,1,1,yes,0,0,0,weapon,0	//CH_SOULCOLLECT#狂気功#
-402,8,6,1,0,1,10,1,no,0,0,0,none,0	//PF_MINDBREAKER#?インドブレ?カ?#
+402,8,6,1,0,1,5,1,no,0,0,0,none,0	//PF_MINDBREAKER#?インドブレ?カ?#
 403,0,0,4,0,1,1,1,yes,0,0,0,magic,0	//PF_MEMORIZE#メモライズ#
 404,3,6,2,2,1,5,1,yes,0,256,1,magic,0	//PF_FOGWALL#フォグウォ?ル#
 405,3,6,2,0,1,1,1,no,0,128,2,misc,0	//PF_SPIDERWEB#スパイ??ウェッブ#
-406,-1,6,1,0,2,10,1,no,33,0,0,weapon,0	//ASC_METEORASSAULT#メテオアサルト#
+406,0,6,4,0,1,10,1,no,33,0,0,weapon,0	//ASC_METEORASSAULT#メテオアサルト#
 407,0,6,4,0,1,1,0,no,0,0,0,none,0	//ASC_CDP#デッドリ??イズン製造#
 408,0,0,4,0,1,1,1,yes,0,0,0,magic,0	//WE_BABY##
 409,0,0,4,0,1,1,1,yes,0,0,0,magic,0	//WE_CALLPARENT##

+ 31 - 0
src/common/core.c

@@ -76,6 +76,11 @@ sigfunc *compat_signal(int signo, sigfunc *func)
 static void sig_proc(int sn)
 {
 	int i;
+	static int is_called = 0;
+
+	if(is_called++)
+		return;
+
 	switch(sn){
 	case SIGINT:
 	case SIGTERM:
@@ -196,11 +201,37 @@ static void display_title(void)
  */
 
 int runflag = 1;
+char pid_file[256];
+
+void pid_delete(void) {
+	unlink(pid_file);
+}
+
+void pid_create(const char* file) {
+	FILE *fp;
+	int len = strlen(file);
+	strcpy(pid_file,file);
+	if(len > 4 && pid_file[len - 4] == '.') {
+		pid_file[len - 4] = 0;
+	}
+	strcat(pid_file,".pid");
+	fp = fopen(pid_file,"w");
+	if(fp) {
+#ifdef _WIN32
+		fprintf(fp,"%d",GetCurrentProcessId());
+#else
+		fprintf(fp,"%d",getpid());
+#endif
+		fclose(fp);
+		atexit(pid_delete);
+	}
+}
 
 int main(int argc,char **argv)
 {
 	int next;
 
+	pid_create(argv[0]);
 	Net_Init();
 	do_socket();
 	

+ 90 - 16
src/common/db.c

@@ -354,6 +354,29 @@ static void db_rebalance_erase(struct dbn *z,struct dbn **root)
 	}
 }
 
+void db_free_lock(struct dbt *table) {
+	table->free_lock++;
+}
+
+void db_free_unlock(struct dbt *table) {
+	if(--table->free_lock == 0) {
+		int i;
+		for(i = 0; i < table->free_count ; i++) {
+			db_rebalance_erase(table->free_list[i].z,table->free_list[i].root);
+			if(table->cmp == strdb_cmp) {
+				free(table->free_list[i].z->key);
+			}
+#ifdef MALLOC_DBN
+			free_dbn(table->free_list[i].z);
+#else
+			free(table->free_list[i].z);
+#endif
+			table->item_count--;
+		}
+		table->free_count = 0;
+	}
+}
+
 struct dbn* db_insert(struct dbt *table,void* key,void* data)
 {
 	struct dbn *p,*priv;
@@ -363,10 +386,33 @@ struct dbn* db_insert(struct dbt *table,void* key,void* data)
 	for(c=0,priv=NULL ,p = table->ht[hash];p;){
 		c=table->cmp(table,key,p->key);
 		if(c==0){ // replace
-                        if (table->release)
-                            table->release(p, 3);
+			if (table->release)
+				table->release(p, 3);
+			if(p->deleted) {
+				// 削除されたデータなので、free_list 上の削除予定を消す
+				int i;
+				for(i = 0; i < table->free_count ; i++) {
+					if(table->free_list[i].z == p) {
+						memmove(
+							&table->free_list[i],
+							&table->free_list[i+1],
+							sizeof(struct db_free)*(table->free_count - i - 1)
+						);
+						break;
+					}
+				}
+				if(i == table->free_count || table->free_count <= 0) {
+					printf("db_insert: cannnot find deleted db node.\n");
+				} else {
+					table->free_count--;
+					if(table->cmp == strdb_cmp) {
+						free(p->key);
+					}
+				}
+			}
 			p->data=data;
 			p->key=key;
+			p->deleted = 0;
 			return p;
 		}
 		priv=p;
@@ -391,6 +437,7 @@ struct dbn* db_insert(struct dbt *table,void* key,void* data)
 	p->key   = key;
 	p->data  = data;
 	p->color = RED;
+	p->deleted = 0;
 	if(c==0){ // hash entry is empty
 		table->ht[hash] = p;
 		p->color = BLACK;
@@ -429,25 +476,47 @@ void* db_erase(struct dbt *table,void* key)
 	if(!p)
 		return NULL;
 	data=p->data;
-	db_rebalance_erase(p,&table->ht[hash]);
-#ifdef MALLOC_DBN
-	free_dbn(p);
-#else
-	aFree(p);
-#endif
-	table->item_count--;
+	if(table->free_lock) {
+		if(table->free_count == table->free_max) {
+			table->free_max += 32;
+			table->free_list = (struct db_free*)realloc(table->free_list,sizeof(struct db_free) * table->free_max);
+		}
+		table->free_list[table->free_count].z    = p;
+		table->free_list[table->free_count].root = &table->ht[hash];
+		table->free_count++;
+		p->deleted = 1;
+		p->data    = NULL;
+		if(table->cmp == strdb_cmp) {
+			if(table->maxlen) {
+				char *key = (char*)malloc(table->maxlen);
+				memcpy(key,p->key,table->maxlen);
+				p->key = key;
+			} else {
+				p->key = strdup((const char*)p->key);
+			}
+		}
+	} else {
+		db_rebalance_erase(p,&table->ht[hash]);
+	#ifdef MALLOC_DBN
+		free_dbn(p);
+	#else
+		aFree(p);
+	#endif
+		table->item_count--;
+	}
 	return data;
 }
 
 void db_foreach(struct dbt *table,int (*func)(void*,void*,va_list),...)
 {
 	int i,sp;
-	int count = 0;
+	int count = table->item_count;
 	// red-black treeなので64個stackがあれば2^32個ノードまで大丈夫
 	struct dbn *p,*pn,*stack[64];
 	va_list ap;
 
 	va_start(ap,func);
+	db_free_lock(table);
 	for(i=0;i<HASH_SIZE;i++){
 		if((p=table->ht[i])==NULL)
 			continue;
@@ -457,8 +526,9 @@ void db_foreach(struct dbt *table,int (*func)(void*,void*,va_list),...)
 			//if (!p->data) {
 			//	printf("Warning: no data for key %d in db_foreach (db.c) !\n",(int)p->key);
 			//} else {
-			func(p->key, p->data, ap);
-			count++;
+			if(!p->deleted)
+				func(p->key, p->data, ap);
+			count--;
 			//}
 			if((pn=p->left)!=NULL){
 				if(p->right){
@@ -476,10 +546,11 @@ void db_foreach(struct dbt *table,int (*func)(void*,void*,va_list),...)
 			}
 		}
 	}
-	if(count != table->item_count) {
+	db_free_unlock(table);
+	if(count) {
 		printf(
-			"db_foreach : data lost %d of %d item(s) allocated from %s line %d\n",
-			table->item_count - count,count,table->alloc_file,table->alloc_line
+			"db_foreach : data lost %d item(s) allocated from %s line %d\n",
+			count,table->alloc_file,table->alloc_line
 		);
 	}
 	va_end(ap);
@@ -492,12 +563,13 @@ void db_final(struct dbt *table,int (*func)(void*,void*,va_list),...)
 	va_list ap;
 
 	va_start(ap,func);
+	db_free_lock(table);
 	for(i=0;i<HASH_SIZE;i++){
 		if((p=table->ht[i])==NULL)
 			continue;
 		sp=0;
 		while(1){
-			if(func)
+			if(func && !p->deleted)
 				func(p->key,p->data,ap);
 			if((pn=p->left)!=NULL){
 				if(p->right){
@@ -520,6 +592,8 @@ void db_final(struct dbt *table,int (*func)(void*,void*,va_list),...)
 			p=pn;
 		}
 	}
+	db_free_unlock(table);
+	free(table->free_list);
 	aFree(table);
 	va_end(ap);
 }

+ 11 - 1
src/common/db.h

@@ -13,6 +13,7 @@ struct dbn {
 	int color;
 	void *key;
 	void *data;
+	int deleted;	// 削除済みフラグ(db_foreach)
 };
 
 struct dbt {
@@ -24,7 +25,16 @@ struct dbt {
 	struct dbn *ht[HASH_SIZE];
 	int item_count; // vf?
 	const char* alloc_file; // DB?t@C
-	int         alloc_line; // DB?s
+	int alloc_line; // DB?s
+	// db_foreach 内部でdb_erase される対策として、
+	// db_foreach が終わるまでロックすることにする
+	struct db_free {
+		struct dbn *z;
+		struct dbn **root;
+	} *free_list;
+	int free_count;
+	int free_max;
+	int free_lock;
 };
 
 #define strdb_search(t,k)   db_search((t),(void*)(k))

+ 43 - 0
src/map/atcommand.c

@@ -213,6 +213,7 @@ ACMD_FUNC(mobsearch);
 ACMD_FUNC(cleanmap);
 ACMD_FUNC(npctalk);
 ACMD_FUNC(pettalk);
+ACMD_FUNC(users);
 ACMD_FUNC(autoloot);  // by Upa-Kun
 
 #ifndef TXT_ONLY
@@ -489,6 +490,7 @@ static AtCommandInfo atcommand_info[] = {
 	{ AtCommand_CleanMap,			"@cleanmap",		 0, atcommand_cleanmap },
 	{ AtCommand_NpcTalk,			"@npctalk",			 0,	atcommand_npctalk },
 	{ AtCommand_PetTalk,			"@pettalk",			 0,	atcommand_pettalk },
+	{ AtCommand_Users,				"@users",		 0, atcommand_users },
 	{ AtCommand_ResetState,			"/reset",			40,	NULL },
 
 #ifndef TXT_ONLY // sql-only commands
@@ -7838,6 +7840,47 @@ atcommand_pettalk(
 	return 0;
 }
 
+/*==========================================
+ * @users
+ * サーバー内の人数マップを表示させる
+ * 手抜きのため汚くなっているのは仕様です。
+ *------------------------------------------
+ */
+
+static struct dbt *users_db;
+static int users_all;
+
+static int atcommand_users_sub1(struct map_session_data* sd,va_list va) {
+	int users = (int)strdb_search(users_db,sd->mapname) + 1;
+	users_all++;
+	strdb_insert(users_db,sd->mapname,(void *)users);
+	return 0;
+}
+
+static int atcommand_users_sub2(void* key,void* val,va_list va) {
+	char buf[256];
+	struct map_session_data* sd = va_arg(va,struct map_session_data*);
+	sprintf(buf,"%s : %d (%d%%)",(char *)key,(int)val,(int)val * 100 / users_all);
+	clif_displaymessage(sd->fd,buf);
+	return 0;
+}
+
+int
+atcommand_users(
+	const int fd, struct map_session_data* sd,
+	const char* command, const char* message)
+{
+	char buf[256];
+	users_all = 0;
+	users_db = strdb_init(24);
+	clif_foreachclient(atcommand_users_sub1);
+	strdb_foreach(users_db,atcommand_users_sub2,sd);
+	sprintf(buf,"all : %d",users_all);
+	clif_displaymessage(fd,buf);
+	strdb_final(users_db,NULL);
+	return 0;
+}
+
 /*==========================================
  *
  *------------------------------------------

+ 1 - 0
src/map/atcommand.h

@@ -198,6 +198,7 @@ enum AtCommandType {
 	AtCommand_CleanMap,
 	AtCommand_NpcTalk,
 	AtCommand_PetTalk,
+	AtCommand_Users,
 
 	// SQL-only commands start
 #ifndef TXT_ONLY

+ 19 - 49
src/map/battle.c

@@ -400,7 +400,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i
 
 	if(class_ == 1288 || class_ == 1287 || class_ == 1286 || class_ == 1285) {
 //	if(class_ == 1288) {
-		if(class_ == 1288 && flag&BF_SKILL)
+		if(class_ == 1288 && (flag&BF_SKILL || skill_num == ASC_BREAKER))
 			damage=0;
 		if(src->type == BL_PC) {
 			struct guild *g=guild_search(((struct map_session_data *)src)->status.guild_id);
@@ -417,6 +417,8 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i
 				damage=0;//正規ギルド承認がないとダメージ無し
 			else if (battle_config.guild_max_castles != 0 && guild_checkcastles(g)>=battle_config.guild_max_castles)
 				damage = 0; // [MouseJstr]
+			else if (g && gc && guild_check_alliance(gc->guild_id, g->guild_id, 0) == 1)
+				return 0;
 		}
 		else damage = 0;
 	}
@@ -775,7 +777,6 @@ static struct Damage battle_calc_pet_weapon_attack(
 				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;
@@ -1271,7 +1272,6 @@ static struct Damage battle_calc_mob_weapon_attack(
 				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;
@@ -1615,7 +1615,6 @@ static struct Damage battle_calc_pc_weapon_attack(
 	int no_cardfix=0;
 	int def1 = status_get_def(target);
 	int def2 = status_get_def2(target);
-//	int mdef1, mdef2;
 	int t_vit = status_get_vit(target);
 	struct Damage wd;
 	int damage,damage2,damage3=0,damage4=0,type,div_,blewcount=skill_get_blewcount(skill_num,skill_lv);
@@ -2024,6 +2023,7 @@ static struct Damage battle_calc_pc_weapon_attack(
 			case KN_SPEARSTAB:	// スピアスタブ
 				damage = damage*(100+ 15*skill_lv)/100;
 				damage2 = damage2*(100+ 15*skill_lv)/100;
+				blewcount=0;
 				break;
 			case KN_SPEARBOOMERANG:	// スピアブーメラン
 				damage = damage*(100+ 50*skill_lv)/100;
@@ -2047,7 +2047,6 @@ static struct Damage battle_calc_pc_weapon_attack(
 				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;
@@ -2287,49 +2286,12 @@ static struct Damage battle_calc_pc_weapon_attack(
 				break;
 			case ASC_BREAKER:		// -- moonsoul (special damage for ASC_BREAKER skill)
 				if(sd){
-/*					int mdef1=status_get_mdef(target);
-					int mdef2=status_get_mdef2(target);
-					int imdef_flag=0;
-
-					damage = ((damage * 5) + (skill_lv * status_get_int(src) * 5) + rand()%500 + 500) /2;
-					damage2 = ((damage2 * 5) + (skill_lv * status_get_int(src) * 5) + rand()%500 + 500) /2;
-					damage3 = damage;
-					// physical damage can miss
-					hitrate = 1000000;*/
-
 					// calculate physical part of damage
 					damage = damage * skill_lv;
 					damage2 = damage2 * skill_lv;
-					// element modifier added right after this
-
 					// calculate magic part of damage
 					damage3 = skill_lv * status_get_int(src) * 5;
 
-					// ignores magic defense now [Celest]
-					/*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_, status_get_element(target) );*/
-
 					flag=(flag&~BF_RANGEMASK)|BF_LONG;
 				}
 				break;
@@ -3221,7 +3183,7 @@ struct Damage  battle_calc_misc_attack(
 	struct Damage md;
 	int damagefix=1;
 
-	int aflag=BF_MISC|BF_LONG|BF_SKILL;
+	int aflag=BF_MISC|BF_SHORT|BF_SKILL;
 
 	//return前の処理があるので情報出力部のみ変更
 	if( bl == NULL || target == NULL ){
@@ -3263,13 +3225,13 @@ struct Damage  battle_calc_misc_attack(
 		damage=(dex/10+int_/2+skill*3+40)*2;
 		if(flag > 1)
 			damage /= flag;
-		if(status_get_mode(target) & 0x40)
-			damage = 1;
+		aflag |= (flag&~BF_RANGEMASK)|BF_LONG;
 		break;
 
 	case TF_THROWSTONE:	// 石投げ
 		damage=50;
 		damagefix=0;
+		aflag |= (flag&~BF_RANGEMASK)|BF_LONG;
 		break;
 
 	case BA_DISSONANCE:	// 不協和音
@@ -3312,8 +3274,7 @@ struct Damage  battle_calc_misc_attack(
 #endif
 		if(flag > 1)
 			damage /= flag;
-		if(status_get_mode(target) & 0x40)
-			damage = 1;
+		aflag |= (flag&~BF_RANGEMASK)|BF_LONG;
 		break;
 	}
 
@@ -3348,6 +3309,9 @@ struct Damage  battle_calc_misc_attack(
 		damage = div_;
 	}
 
+	if(status_get_mode(target)&0x40 && damage>0)
+		damage = 1;
+
 	damage=battle_calc_damage(bl,target,damage,div_,skill_num,skill_lv,aflag);	// 最終修正
 
 	md.damage=damage;
@@ -3476,7 +3440,7 @@ int battle_weapon_attack( struct block_list *src,struct block_list *target,
 				}
 			}
 			if(rdamage > 0)
-				clif_damage(src,src,tick, wd.amotion,0,rdamage,1,4,0);
+				clif_damage(src,src,tick,wd.amotion,wd.dmotion,rdamage,1,4,0);
 		}
 
 		if (wd.div_ == 255 && sd)	{ //三段掌
@@ -3925,7 +3889,7 @@ int battle_check_range(struct block_list *src,struct block_list *bl,int range)
 //		return 1;
 
 	// 障害物判定
-	return path_search_long(src->m,src->x,src->y,bl->x,bl->y);
+	return path_search_long(NULL,src->m,src->x,src->y,bl->x,bl->y);
 }
 
 /*==========================================
@@ -4122,6 +4086,9 @@ static const struct {
 	{ "gm_can_drop_lv",				       &battle_config.gm_can_drop_lv			},
 	{ "disp_hpmeter",				       &battle_config.disp_hpmeter				},
 	{ "bone_drop",				           &battle_config.bone_drop				},
+	{ "monster_damage_delay",				&battle_config.monster_damage_delay		},
+
+// eAthena additions
 	{ "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
@@ -4369,6 +4336,9 @@ void battle_set_defaults() {
 	battle_config.gm_can_drop_lv = 0;
 	battle_config.disp_hpmeter = 0;
 	battle_config.bone_drop = 0;
+	battle_config.monster_damage_delay = 1;
+
+// eAthena additions
 	battle_config.item_rate_common = 100;
 	battle_config.item_rate_equip = 100;
 	battle_config.item_rate_card = 100;

+ 2 - 0
src/map/battle.h

@@ -280,7 +280,9 @@ extern struct Battle_Config {
 	int gm_can_drop_lv;
 	int disp_hpmeter;
 	int bone_drop;
+	int monster_damage_delay;
 
+// eAthena additions
 	int night_at_start; // added by [Yor]
 	int day_duration; // added by [Yor]
 	int night_duration; // added by [Yor]

+ 1 - 1
src/map/chrif.c

@@ -1006,7 +1006,7 @@ int chrif_disconnect_sub(struct map_session_data* sd,va_list va) {
 
 int chrif_disconnect(int fd) {
 	if(fd == char_fd) {
-		char_fd = -1;
+		char_fd = 0;
 		sprintf(tmp_output,"Map Server disconnected from Char Server.\n\n");
 		ShowWarning(tmp_output);
 		clif_foreachclient(chrif_disconnect_sub);

+ 25 - 9
src/map/guild.c

@@ -678,11 +678,10 @@ int guild_member_leaved(int guild_id,int account_id,int char_id,int flag,
 {
 	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++)
+		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;
@@ -698,6 +697,12 @@ int guild_member_leaved(int guild_id,int account_id,int char_id,int flag,
 				g->member[i].account_id=0;
 				g->member[i].sd=NULL;
 			}
+			// メンバーリストを全員に再通知
+			for(i=0;i<g->max_member;i++){
+				if( g->member[i].sd!=NULL )
+					clif_guild_memberlist(g->member[i].sd);
+			}
+		}
 	}
 	if(sd!=NULL) {
 		if (sd->status.guild_id==guild_id){
@@ -706,13 +711,7 @@ int guild_member_leaved(int guild_id,int account_id,int char_id,int flag,
 			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更新送信
@@ -1037,6 +1036,23 @@ int guild_get_alliance_count(struct guild *g,int flag)
 	}
 	return c;
 }
+// 同盟関係かどうかチェック
+// 同盟なら1、それ以外は0
+int guild_check_alliance(int guild_id1, int guild_id2, int flag)
+{
+	struct guild *g;
+	int i;
+
+	g = guild_search(guild_id1);
+	if (g == NULL)
+		return 0;
+
+	for (i=0; i<MAX_GUILDALLIANCE; i++)
+		if ((g->alliance[i].guild_id == guild_id2) && (g->alliance[i].opposition == flag))
+			return 1;
+
+	return 0;
+}
 // ギルド同盟要求
 int guild_reqalliance(struct map_session_data *sd,int account_id)
 {

+ 1 - 0
src/map/guild.h

@@ -54,6 +54,7 @@ int guild_allianceack(int guild_id1,int guild_id2,int account_id1,int account_id
 	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_check_alliance(int guild_id1, int guild_id2, int flag);
 
 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_);

+ 91 - 71
src/map/map.c

@@ -239,10 +239,27 @@ int map_freeblock_unlock(void) {
 	}else if(block_free_lock<0){
 		if(battle_config.error_log)
 			printf("map_freeblock_unlock: lock count < 0 !\n");
+		block_free_lock = 0; // 次回以降のロックに支障が出てくるのでリセット
 	}
 	return block_free_lock;
 }
 
+// map_freeblock_lock() を呼んで map_freeblock_unlock() を呼ばない
+// 関数があったので、定期的にblock_free_lockをリセットするようにする。
+// この関数は、do_timer() のトップレベルから呼ばれるので、
+// block_free_lock を直接いじっても支障無いはず。
+
+int map_freeblock_timer(int tid,unsigned int tick,int id,int data) {
+	if(block_free_lock > 0) {
+		printf("map_freeblock_timer: block_free_lock(%d) is invalid.\n",block_free_lock);
+		block_free_lock = 1;
+		map_freeblock_unlock();
+	}
+	// else {
+	// 	printf("map_freeblock_timer: check ok\n");
+	// }
+	return 0;
+}
 
 //
 // block化?理
@@ -1428,96 +1445,98 @@ void map_addnickdb(struct map_session_data *sd) {
 int map_quit(struct map_session_data *sd) {
 	nullpo_retr(0, sd);
 
-	if (sd->state.event_disconnect) {
-		struct npc_data *npc;
-		if ((npc = npc_name2id(script_config.logout_event_name))) {
-			run_script(npc->u.scr.script,0,sd->bl.id,npc->bl.id); // PCLogoutNPC
-			sprintf (tmp_output, "Event '"CL_WHITE"%s"CL_RESET"' executed.\n", script_config.logout_event_name);
-			ShowStatus(tmp_output);
+	if(!sd->state.waitingdisconnect) {
+		if (sd->state.event_disconnect) {
+			struct npc_data *npc;
+			if ((npc = npc_name2id(script_config.logout_event_name))) {
+				run_script(npc->u.scr.script,0,sd->bl.id,npc->bl.id); // PCLogoutNPC
+				sprintf (tmp_output, "Event '"CL_WHITE"%s"CL_RESET"' executed.\n", script_config.logout_event_name);
+				ShowStatus(tmp_output);
+			}
 		}
-	}
 
-	if(sd->chatID)	// チャットから出る
-		chat_leavechat(sd);
+		if(sd->chatID)	// チャットから出る
+			chat_leavechat(sd);
 
-	if(sd->trade_partner)	// 取引を中?する
-		trade_tradecancel(sd);
+		if(sd->trade_partner)	// 取引を中?する
+			trade_tradecancel(sd);
 
-	if(sd->party_invite>0)	// パ?ティ?誘を拒否する
-		party_reply_invite(sd,sd->party_invite_account,0);
+		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);
+		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);	// パ?ティのログアウトメッセ?ジ送信
+		party_send_logout(sd);	// パ?ティのログアウトメッセ?ジ送信
 
-	guild_send_memberinfoshort(sd,0);	// ギルドのログアウトメッセ?ジ送信
+		guild_send_memberinfoshort(sd,0);	// ギルドのログアウトメッセ?ジ送信
 
-	pc_cleareventtimer(sd);	// イベントタイマを破棄する
+		pc_cleareventtimer(sd);	// イベントタイマを破棄する
 
-	if(sd->state.storage_flag)
-		storage_guild_storage_quit(sd,0);
-	else
-		storage_storage_quit(sd);	// 倉庫を開いてるなら保存する
-
-	// check if we've been authenticated [celest]
-	if (sd->state.auth)
-		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;
+		if(sd->state.storage_flag)
+			storage_guild_storage_quit(sd,0);
+		else
+			storage_storage_quit(sd);	// 倉庫を開いてるなら保存する
 
-	status_change_clear(&sd->bl,1);	// ステ?タス異常を解除する
-	skill_clear_unitgroup(&sd->bl);	// スキルユニットグル?プの削除
-	skill_cleartimerskill(&sd->bl);
+		// check if we've been authenticated [celest]
+		if (sd->state.auth)
+			skill_castcancel(&sd->bl,0);	// 詠唱を中?する
 
-	// check if we've been authenticated [celest]
-	if (sd->state.auth) {
-		pc_stop_walking(sd,0);
-		pc_stopattack(sd);
-		pc_delinvincibletimer(sd);
-	}
-	pc_delspiritball(sd,sd->spiritball,1);
-	skill_gangsterparadise(sd,0);
+		skill_stop_dancing(&sd->bl,1);// ダンス/演奏中?
 
-	if (sd->state.auth)
-		status_calc_pc(sd,4);
-//	skill_clear_unitgroup(&sd->bl);	// [Sara-chan]
+		if(sd->sc_data && sd->sc_data[SC_BERSERK].timer!=-1) //バ?サ?ク中の終了はHPを100に
+			sd->status.hp = 100;
 
-	clif_clearchar_area(&sd->bl,2);
+		status_change_clear(&sd->bl,1);	// ステ?タス異常を解除する
+		skill_clear_unitgroup(&sd->bl);	// スキルユニットグル?プの削除
+		skill_cleartimerskill(&sd->bl);
 
-	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;
+		// check if we've been authenticated [celest]
+		if (sd->state.auth) {
+			pc_stop_walking(sd,0);
+			pc_stopattack(sd);
+			pc_delinvincibletimer(sd);
+		}
+		pc_delspiritball(sd,sd->spiritball,1);
+		skill_gangsterparadise(sd,0);
+		skill_unit_move(&sd->bl,gettick(),0);
+
+		if (sd->state.auth)
+			status_calc_pc(sd,4);
+	//	skill_clear_unitgroup(&sd->bl);	// [Sara-chan]
+
+		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);
 		}
-		else
-			intif_save_petdata(sd->status.account_id,&sd->pet);
-	}
 
-	if(pc_isdead(sd))
-		pc_setrestartvalue(sd,2);
+		if(pc_isdead(sd))
+			pc_setrestartvalue(sd,2);
 
-	pc_makesavestatus(sd);
-	chrif_save(sd);
-	storage_storage_dirty(sd);
-	storage_storage_save(sd);
+		pc_makesavestatus(sd);
+		chrif_save(sd);
+		storage_storage_dirty(sd);
+		storage_storage_save(sd);
+		map_delblock(&sd->bl);
+	}
 
 	if( sd->npc_stackbuf && sd->npc_stackbuf != NULL) {
 		aFree( sd->npc_stackbuf );
 		sd->npc_stackbuf = NULL;
 	}
 
-	map_delblock(&sd->bl);
-
 #ifndef TXT_ONLY
 	chrif_char_offline(sd);
 #endif
@@ -3348,11 +3367,16 @@ int do_init(int argc, char *argv[]) {
 
 	map_readallmap();
 
+	add_timer_func_list(map_freeblock_timer,"map_freeblock_timer");
 	add_timer_func_list(map_clearflooritem_timer, "map_clearflooritem_timer");
+	add_timer_interval(gettick()+1000,map_freeblock_timer,0,0,60*1000);
 
 	//Added by Mugendai for GUI support
 	if (flush_on)
 		add_timer_interval(gettick()+10, flush_timer,0,0,flush_time);
+	//Added for Mugendais I'm Alive mod
+	if (imalive_on)
+		add_timer_interval(gettick()+10, imalive_timer,0,0,imalive_time*1000);
 
 #ifndef TXT_ONLY // online status timer, checks every hour [Valaris]
 	add_timer_func_list(online_timer, "online_timer");
@@ -3395,10 +3419,6 @@ int do_init(int argc, char *argv[]) {
 	if (battle_config.pk_mode == 1)
 		ShowNotice("Server is running on '"CL_WHITE"PK Mode"CL_RESET"'.\n");
 
-	//Added for Mugendais I'm Alive mod
-	if (imalive_on)
-		add_timer_interval(gettick()+10, imalive_timer,0,0,imalive_time*1000);
-
 	sprintf(tmp_output,"Server is '"CL_GREEN"ready"CL_RESET"' and listening on port '"CL_WHITE"%d"CL_RESET"'.\n\n", map_port);
 	ShowStatus(tmp_output);
 

+ 7 - 1
src/map/map.h

@@ -53,6 +53,12 @@ struct walkpath_data {
 	unsigned char path_len,path_pos,path_half;
 	unsigned char path[MAX_WALKPATH];
 };
+struct shootpath_data {
+	int rx,ry,len;
+	int x[MAX_WALKPATH];
+	int y[MAX_WALKPATH];
+};
+
 struct script_reg {
 	int index;
 	int data;
@@ -774,7 +780,7 @@ 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_search_long(int m,int x0,int y0,int x1,int y1);
+int path_search_long(struct shootpath_data *,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);

+ 10 - 7
src/map/mob.c

@@ -1103,7 +1103,7 @@ int mob_stop_walking(struct mob_data *md,int type)
 	if(type&0x02) {
 		int delay=status_get_dmotion(&md->bl);
 		unsigned int tick = gettick();
-		if(md->canmove_tick < tick)
+		if(battle_config.monster_damage_delay && md->canmove_tick < tick)
 			md->canmove_tick = tick + delay;
 	}
 
@@ -2225,7 +2225,7 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
 		return 0;
 	}
 
-	if(md->sc_data[SC_ENDURE].timer == -1)
+	if(battle_config.monster_damage_delay && md->sc_data[SC_ENDURE].timer == -1)
 		mob_stop_walking(md,3);
 	if(damage > max_hp>>2)
 		skill_stop_dancing(&md->bl,0);
@@ -3777,11 +3777,14 @@ int mob_gvmobcheck(struct map_session_data *sd, struct block_list *bl)
 			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;//正規ギルド承認がないとダメージ無し
-
+		else if(g) {
+			if (gc != NULL && g->guild_id == gc->guild_id)
+				return 0;//自占領ギルドのエンペならダメージ無し
+			else if(guild_checkskill(g,GD_APPROVAL) <= 0 && md->class_ == 1288)
+				return 0;//正規ギルド承認がないとダメージ無し
+			else if (gc && guild_check_alliance(gc->guild_id, g->guild_id, 0) == 1)
+				return 0;	// 同盟ならダメージ無し
+		}
 	}
 
 	return 1;

+ 6 - 0
src/map/npc.c

@@ -1882,9 +1882,15 @@ static int npc_parse_script(char *w1,char *w2,char *w3,char *w4,char *first_line
 				printf("npc_parse_script: label name error !\n");
 				exit(1);
 			}else{
+				struct event_data *ev2;
 				ev->nd=nd;
 				ev->pos=pos;
 				sprintf(buf,"%s::%s",nd->exname,lname);
+				ev2 = strdb_search(ev_db,buf);
+				if(ev2 != NULL) {
+					printf("npc_parse_script : duplicate event %s\n",buf);
+					free(ev2);
+				}
 				strdb_insert(ev_db,buf,ev);
 			}
 		}

+ 20 - 3
src/map/path.c

@@ -246,7 +246,7 @@ int path_blownpos(int m,int x0,int y0,int dx,int dy,int count)
  *------------------------------------------
  */
 #define swap(x,y) { int t; t = x; x = y; y = t; }
-int path_search_long(int m,int x0,int y0,int x1,int y1)
+int path_search_long(struct shootpath_data *spd,int m,int x0,int y0,int x1,int y1)
 {
 	int dx, dy;
 	int wx = 0, wy = 0;
@@ -265,13 +265,25 @@ int path_search_long(int m,int x0,int y0,int x1,int y1)
 	}
 	dy = (y1 - y0);
 
+	if (spd) {
+		spd->rx = spd->ry = 0;
+		spd->len = 1;
+		spd->x[0] = x0;
+		spd->y[0] = y0;
+	}
+
 	if (map_getcellp(md,x1,y1,CELL_CHKWALL))
 		return 0;
 
-	if (dx > abs(dy))
+	if (dx > abs(dy)) {
 		weight = dx;
-	else
+		if (spd)
+			spd->ry=1;
+	} else {
 		weight = abs(y1 - y0);
+		if (spd)
+			spd->rx=1;
+	}
 
 	while (x0 != x1 || y0 != y1) {
 		if (map_getcellp(md,x0,y0,CELL_CHKWALL))
@@ -289,6 +301,11 @@ int path_search_long(int m,int x0,int y0,int x1,int y1)
 			wy += weight;
 			y0 --;
 		}
+		if (spd && spd->len<MAX_WALKPATH) {
+			spd->x[spd->len] = x0;
+			spd->y[spd->len] = y0;
+			spd->len++;
+		}
 	}
 
 	return 1;

+ 21 - 22
src/map/pc.c

@@ -371,22 +371,24 @@ int pc_makesavestatus(struct map_session_data *sd)
 		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)
+	if(!sd->state.waitingdisconnect) {
+		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,&m->save,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に
@@ -585,10 +587,8 @@ int pc_isequip(struct map_session_data *sd,int n)
 //装備破壊
 int pc_break_equip(struct map_session_data *sd, unsigned short where)
 {
-	struct item_data* item;
 	int i;
 	int sc;
-	char output[255];
 
 	nullpo_retr(-1, sd);
 	if(sd->unbreakable_equip & where)
@@ -616,13 +616,12 @@ int pc_break_equip(struct map_session_data *sd, unsigned short where)
 
 	for (i=0;i<MAX_INVENTORY;i++) {
 		if (sd->status.inventory[i].equip & where &&
-			!sd->status.inventory[i].attribute == 1) {
-			item=sd->inventory_data[i];
+			sd->status.inventory[i].attribute != 1) {
 			sd->status.inventory[i].attribute = 1;
 			pc_unequipitem(sd,i,3);
-			sprintf(output, "%s has broken.",item->jname);
+			sprintf(tmp_output, "%s has broken.",sd->inventory_data[i]->jname);
 			clif_emotion(&sd->bl,23);
-			clif_displaymessage(sd->fd, output);
+			clif_displaymessage(sd->fd, tmp_output);
 			clif_equiplist(sd);
 			break;
 		}
@@ -6823,7 +6822,7 @@ static int pc_autosave_sub(struct map_session_data *sd,va_list ap)
 
 	Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd);
 
-	if(save_flag==0 && sd->fd>last_save_fd){
+	if(save_flag==0 && sd->fd>last_save_fd && !sd->state.waitingdisconnect){
 		struct guild_castle *gc=NULL;
 		int i;
 //		if(battle_config.save_log)

+ 4 - 4
src/map/script.c

@@ -1725,7 +1725,7 @@ int buildin_menu(struct script_state *st)
 			conv_str(st,& (st->stack->stack_data[i]));
 			len+=strlen(st->stack->stack_data[i].u.str)+1;
 		}
-		buf=(char *)aCallocA(len,sizeof(char));
+		buf=(char *)aCallocA(len+1,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);
@@ -6326,7 +6326,7 @@ int buildin_select(struct script_state *st)
 			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=(char *)aCalloc(len+1,sizeof(char));
 		buf[0]=0;
 		for(i=st->start+2,len=0;i<st->end;i++){
 			strcat(buf,st->stack->stack_data[i].u.str);
@@ -7652,8 +7652,8 @@ int script_config_read(char *cfgName)
 	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;
+	script_config.check_cmdcount=65535;
+	script_config.check_gotocount=2048;
 
 	script_config.die_event_name = (char *)aCallocA(24,sizeof(char));
 	script_config.kill_event_name = (char *)aCallocA(24,sizeof(char));

+ 105 - 96
src/map/skill.c

@@ -1113,7 +1113,7 @@ 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 dir,ret,prev_state=MS_IDLE;
 	int moveblock;
 	struct map_session_data *sd=NULL;
 	struct mob_data *md=NULL;
@@ -1133,16 +1133,15 @@ int skill_blown( struct block_list *src, struct block_list *target,int count)
 		su=(struct skill_unit *)target;
 	}else return 0;
 
-	if(!(count&0x10000)){	/* 指定なしなら位置関係から方向を求める */
-		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=status_get_dir(target);
-		if(dir>=0 && dir<8){
-			dx=-dirx[dir];
-			dy=-diry[dir];
-		}
+	if (count&0xf00000)
+		dir = (count>>20)&0xf;
+	else if (count&0x10000 || (target->x==src->x && target->y==src->y))
+		dir = status_get_dir(target);
+	else
+		dir = map_calc_dir(target,src->x,src->y);
+	if (dir>=0 && dir<8){
+		dx = -dirx[dir];
+		dy = -diry[dir];
 	}
 
 	ret=path_blownpos(target->m,x,y,dx,dy,count&0xffff);
@@ -2093,10 +2092,11 @@ int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int s
 	case AS_SONICBLOW:		/* ソニックブロ? */
 	case KN_PIERCE:			/* ピア?ス */
 	case KN_SPEARBOOMERANG:	/* スピアブ?メラン */
+	case KN_BRANDISHSPEAR:		/* ブランディッシュスピア */
 	case TF_POISON:			/* インベナム */
 	case TF_SPRINKLESAND:	/* 砂まき */
 	case AC_CHARGEARROW:	/* チャ?ジアロ? */
-	case KN_SPEARSTAB:		/* スピアスタブ */
+//	case KN_SPEARSTAB:		/* スピアスタブ */
 	case RG_RAID:		/* サプライズアタック */
 	case RG_INTIMIDATE:		/* インティミデイト */
 	case BA_MUSICALSTRIKE:	/* ミュ?ジカルストライク */
@@ -2135,6 +2135,10 @@ int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int s
 	case NPC_DARKNESSATTACK:
 	case NPC_TELEKINESISATTACK:
 	case NPC_UNDEADATTACK:
+	case NPC_BREAKARMOR:
+	case NPC_BREAKWEAPON:
+	case NPC_BREAKHELM:
+	case NPC_BREAKSHIELD:
 	case LK_AURABLADE:		/* オ?ラブレ?ド */
 	case LK_SPIRALPIERCE:	/* スパイラルピア?ス */
 	case LK_HEADCRUSH:	/* ヘッドクラッシュ */
@@ -2145,6 +2149,7 @@ int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int s
 	case CG_ARROWVULCAN:			/* アロ?バルカン */
 	case ASC_BREAKER:				/* ソウルブレ?カ? */
 	case HW_MAGICCRASHER:		/* マジッククラッシャ? */
+	case ASC_METEORASSAULT:	/* メテオアサルト */
 	case ITM_TOMAHAWK:
 		skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
 		break;
@@ -2188,22 +2193,7 @@ int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int s
 	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 = status_get_dir(bl);
@@ -2310,21 +2300,14 @@ int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int s
 		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  );
 				if (bl->type == BL_MOB && skillid == AS_GRIMTOOTH) {
@@ -2333,22 +2316,20 @@ int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int s
 						status_change_start(bl,SC_SLOWDOWN,0,0,0,0,1000,0);
 				}
 			}
-		}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;
-
-			if (skillid == ASC_METEORASSAULT)
-				clif_skill_nodamage(src,bl,skillid,skilllv,1);
+		} else {
+			int ar;
+			int x = bl->x, y = bl->y;
+			switch (skillid) {
+				case AC_SHOWER:
+					ar=2;
+					break;
+				case NPC_SPLASHATTACK:
+					ar=3;
+					break;
+				default:
+					ar=1;
+					break;
+			}
 
 			skill_area_temp[1]=bl->id;
 			skill_area_temp[2]=x;
@@ -2382,11 +2363,10 @@ int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int s
 			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;	/* 他人から聞いた動きなので間違ってる可能性大&?率が?いっす>< */
+				/* まずターゲットに攻撃を加える */
+				if (!skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0))
+					break;
 				c = skill_get_blewcount(skillid,skilllv);
 				if(map[bl->m].flag.gvg) c = 0;
 				for(i=0;i<c;i++){
@@ -2405,20 +2385,36 @@ int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int s
 					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;
-				skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,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|1,
 					skill_castend_damage_id);
-/*				battle_damage(src,bl,damage,1);
-				if(rdamage > 0)
-					battle_damage(bl,src,rdamage,0);
+		}
+		break;
+	
+	case KN_SPEARSTAB:		/* スピアスタブ */
+		if(flag&1){
+			/* 個別にダメージを与える */
+			if (bl->id==skill_area_temp[1])
+				break;
+			if (skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0x0500))
+				skill_blown(src,bl,skill_area_temp[2]);
+		} else {
+			int x=bl->x,y=bl->y,i,dir;
+			/* まずターゲットに攻撃を加える */
+			dir = map_calc_dir(bl,src->x,src->y);
+			skill_area_temp[1] = bl->id;
+			skill_area_temp[2] = skill_get_blewcount(skillid,skilllv)|dir<<20;
+			if (skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0))
+				skill_blown(src,bl,skill_area_temp[2]);
+			for (i=0;i<4;i++) {
+				map_foreachinarea(skill_area_sub,bl->m,x,y,x,y,0,
+					src,skillid,skilllv,tick,flag|BCT_ENEMY|1,
+					skill_castend_damage_id);
+				x += dirx[dir];
+				y += diry[dir];
 			}
-			map_freeblock_unlock();*/
 		}
 		break;
 
@@ -2441,12 +2437,10 @@ int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int s
 	case WZ_EARTHSPIKE:			/* アーススパイク */
 	case AL_HEAL:				/* ヒール */
 	case AL_HOLYLIGHT:			/* ホーリーライト */
-//	case MG_FROSTDIVER:			/* フロストダイバー */
 	case WZ_JUPITEL:			/* ユピテルサンダー */
 	case NPC_DARKJUPITEL:			/*闇ユピテル*/
 	case NPC_MAGICALATTACK:		/* MOB:魔法打?攻? */
 	case PR_ASPERSIO:			/* アスペルシオ */
-//	case HW_NAPALMVULCAN:		/* ナパームバルカン */
 		skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
 		break;
 
@@ -2465,7 +2459,8 @@ int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int s
 		}
 		damage = skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
 		if (status_get_hp(bl) > 0 && damage > 0 && rand()%100 < rate) {
-			status_change_start(bl,SC_FREEZE,skilllv,0,0,0,skill_get_time2(skillid,skilllv),0);
+			status_change_start(bl,SC_FREEZE,skilllv,0,0,0,
+				skill_get_time2(skillid,skilllv)*(1-sc_def_mdef/100),0);
 		} else if (sd) {
 			clif_skill_fail(sd,skillid,0,0);
 		}
@@ -2631,11 +2626,11 @@ int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int s
 				clif_skill_nodamage(src,bl,skillid,skilllv,1);
 				if (skilllv == 5)
 					skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,0 );
-				if (bl->type == BL_PC) {
+				if (bl->type == BL_PC && (map[src->m].flag.pvp || map[src->m].flag.gvg)) {
 					struct map_session_data *tsd = (struct map_session_data *)bl;
 					if (tsd) {
 						tsd->status.sp = 0;
-						clif_updatestatus((struct map_session_data *)bl,SP_SP);
+						clif_updatestatus(tsd,SP_SP);
 					}
 				}
 			} else {
@@ -3162,6 +3157,7 @@ int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int
 		clif_skill_nodamage(src,bl,skillid,skilllv,1);
 		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);
@@ -3173,9 +3169,11 @@ int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int
 		status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
 		//sd->status.hp = sd->status.max_hp * 3;
 		break;
+
 	case MC_CHANGECART:
 		clif_skill_nodamage(src,bl,skillid,skilllv,1);
 		break;
+
 	case AC_CONCENTRATION:	/* 集中力向上 */
 		{
 			int range = 1;
@@ -3186,6 +3184,7 @@ int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int
 				src,SkillStatusChangeTable[skillid],tick);
 		}
 		break;
+
 	case SM_PROVOKE:		/* プロボック */
 		{
 			struct status_change *sc_data = status_get_sc_data(bl);
@@ -3347,19 +3346,21 @@ int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int
 
 	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);
-		}
+		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);
 		status_change_end(src, SC_HIDING, -1);	// ハイディング解除
 		break;
 
+	case ASC_METEORASSAULT:	/* メテオアサルト */
+		clif_skill_nodamage(src,bl,skillid,skilllv,1);
+		map_foreachinarea(skill_area_sub,
+			bl->m,bl->x-2,bl->y-2,bl->x+2,bl->y+2,0,
+			src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
+			skill_castend_damage_id);
+		break;
+
 	case KN_BRANDISHSPEAR:	/*ブランディッシュスピア*/
 		{
 			int c,n=4,ar;
@@ -3769,35 +3770,36 @@ int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int
 	case ST_FULLSTRIP:	// Celest
 	{
 		struct status_change *tsc_data = status_get_sc_data(bl);
-		int scid, equip, strip_fix, strip_num = 0;
+		int scid, cp_scid = 0, equip, strip_fix, strip_num = 0;
 		scid = SkillStatusChangeTable[skillid];
 		switch (skillid) {
 			case RG_STRIPWEAPON:
 				equip = EQP_WEAPON;
+				cp_scid = SC_CP_WEAPON;
 				break;
 			case RG_STRIPSHIELD:
 				equip = EQP_SHIELD;
+				cp_scid = SC_CP_SHIELD;
 				break;
 			case RG_STRIPARMOR:
 				equip = EQP_ARMOR;
+				cp_scid = SC_CP_ARMOR;
 				break;
 			case RG_STRIPHELM:
 				equip = EQP_HELM;
+				cp_scid = SC_CP_HELM;
 				break;
 			case ST_FULLSTRIP:
 				equip = EQP_WEAPON | EQP_SHIELD | EQP_ARMOR | EQP_HELM;
 				strip_num = 3;
 				break;
 			default:
+				map_freeblock_unlock();
 				return 1;
 		}
 
-		if (tsc_data) {
-			if (tsc_data[scid].timer != -1)
-				break;
-			if (tsc_data[skillid - RG_STRIPWEAPON + SC_CP_WEAPON].timer != -1)
+		if (tsc_data && (tsc_data[scid].timer != -1 || tsc_data[cp_scid].timer != -1))
 				break;
-		}
 		if (dstsd && dstsd->unstripable_equip & equip)
 			break;
 
@@ -3810,7 +3812,7 @@ int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int
 
 		if (dstsd) {
 			for (i=0;i<MAX_INVENTORY;i++) {
-				if (dstsd->status.inventory[i].equip && dstsd->status.inventory[i].equip & equip){
+				if (dstsd->status.inventory[i].equip && (dstsd->status.inventory[i].equip & equip)){
 					pc_unequipitem(dstsd,i,3);
 					if ((--strip_num) <= 0)
 						break;
@@ -4159,28 +4161,31 @@ int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int
 	// Equipment breaking monster skills [Celest]
 	case NPC_BREAKWEAPON:
 		clif_skill_nodamage(src,bl,skillid,skilllv,1);
-		if(bl->type == BL_PC && rand()%100 < skilllv && battle_config.equipment_breaking)
-			pc_breakweapon((struct map_session_data *)bl);
+		if(bl->type == BL_PC && battle_config.equipment_breaking)
+			pc_breakweapon(dstsd);
 		break;
 
 	case NPC_BREAKARMOR:
 		clif_skill_nodamage(src,bl,skillid,skilllv,1);
-		if(bl->type == BL_PC && rand()%100 < skilllv && battle_config.equipment_breaking)
-			pc_breakarmor((struct map_session_data *)bl);
+		if(bl->type == BL_PC && battle_config.equipment_breaking)
+			pc_breakarmor(dstsd);
 		break;
 
 	case NPC_BREAKHELM:
 		clif_skill_nodamage(src,bl,skillid,skilllv,1);
-		if(bl->type == BL_PC && rand()%100 < skilllv && battle_config.equipment_breaking)
-			// since we don't have any code for helm breaking yet...
-			pc_breakweapon((struct map_session_data *)bl);
+		if(bl->type == BL_PC && battle_config.equipment_breaking)
+			pc_breakhelm(dstsd);
 		break;
 
 	case NPC_BREAKSHIELD:
 		clif_skill_nodamage(src,bl,skillid,skilllv,1);
-		if(bl->type == BL_PC && rand()%100 < skilllv && battle_config.equipment_breaking)
-			// since we don't have any code for helm breaking yet...
-			pc_breakweapon((struct map_session_data *)bl);
+		if(bl->type == BL_PC && battle_config.equipment_breaking)
+			pc_breakshield(dstsd);
+		break;
+
+	case NPC_EXPLOSIONSPIRITS:	//NPC爆裂波動
+		clif_skill_nodamage(src,bl,skillid,skilllv,1);
+		status_change_start(bl,SC_EXPLOSIONSPIRITS,skilllv,0,0,0,skill_get_time(skillid,skilllv),0 );
 		break;
 
 	case WE_MALE:				/* 君だけは護るよ */
@@ -4204,10 +4209,12 @@ int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int
 		if(sd && dstsd){
 			if((dstsd = pc_get_partner(sd)) == NULL){
 				clif_skill_fail(sd,skillid,0,0);
+				map_freeblock_unlock();
 				return 0;
 			}
 			if(map[sd->bl.m].flag.nomemo || map[sd->bl.m].flag.nowarpto || map[dstsd->bl.m].flag.nowarp){
 				clif_skill_teleportmessage(sd,1);
+				map_freeblock_unlock();
 				return 0;
 			}
 			skill_unitsetting(src,skillid,skilllv,sd->bl.x,sd->bl.y,0);
@@ -4307,8 +4314,10 @@ int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int
 		break;
 
 	case AS_SPLASHER:		/* ベナムスプラッシャ? */
-		if((double)status_get_max_hp(bl)*2/3 < status_get_hp(bl)) //HPが2/3以上?っていたら失敗
+		if((double)status_get_max_hp(bl)*2/3 < status_get_hp(bl)) { //HPが2/3以上?っていたら失敗
+			map_freeblock_unlock();
 			return 1;
+		}
 		clif_skill_nodamage(src,bl,skillid,skilllv,1);
 		status_change_start(bl,SkillStatusChangeTable[skillid],skilllv,skillid,src->id,skill_get_time(skillid,skilllv),1000,0 );
 		break;

+ 57 - 37
src/map/status.c

@@ -720,7 +720,7 @@ int status_calc_pc(struct map_session_data* sd,int first)
 			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){	// 速度?加
+		if(sd->sc_data[SC_INCREASEAGI].timer!=-1){	// 速度?加
 			sd->paramb[1]+= 2+sd->sc_data[SC_INCREASEAGI].val1;
 			sd->speed -= sd->speed *25/100;
 		}
@@ -1021,13 +1021,12 @@ int status_calc_pc(struct map_session_data* sd,int first)
 
 	//Flee上昇
 	if( (skill=pc_checkskill(sd,TF_MISS))>0 ){	// 回避率?加
-		if(sd->status.class_==6||sd->status.class_==4007 || sd->status.class_==23){
+		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)
+		else 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;
+			sd->speed -= (short)(skill*1.5/100 * DEFAULT_WALK_SPEED);
 	}
 	if( (skill=pc_checkskill(sd,MO_DODGE))>0 )	// 見切り
 		sd->flee += (skill*3)>>1;
@@ -1090,7 +1089,7 @@ int status_calc_pc(struct map_session_data* sd,int first)
 		}
 
 		if(sd->sc_data[SC_VOLCANO].timer!=-1 && sd->def_ele==3){	// ボルケ?ノ
-			sd->watk += sd->sc_data[SC_VIOLENTGALE].val3;
+			sd->watk += sd->sc_data[SC_VOLCANO].val3;
 		}
 
 		if(sd->sc_data[SC_SIGNUMCRUCIS].timer!=-1)
@@ -1663,12 +1662,16 @@ int status_get_max_hp(struct block_list *bl)
 				max_hp += (md->level - mob_db[md->class_].lv) * status_get_vit(bl);
 
 			if(mob_db[md->class_].mexp > 0) {
-				if(battle_config.mvp_hp_rate != 100)
-					max_hp = (max_hp * battle_config.mvp_hp_rate)/100;
+				if(battle_config.mvp_hp_rate != 100) {
+					double hp = (double)max_hp * battle_config.mvp_hp_rate / 100.0;
+					max_hp = (hp > 0x7FFFFFFF ? 0x7FFFFFFF : (int)hp);
+				}
 			}
 			else {
-				if(battle_config.monster_hp_rate != 100)
-					max_hp = (max_hp * battle_config.monster_hp_rate)/100;
+				if(battle_config.mvp_hp_rate != 100) {
+					double hp = (double)max_hp * battle_config.mvp_hp_rate / 100.0;
+					max_hp = (hp > 0x7FFFFFFF ? 0x7FFFFFFF : (int)hp);
+				}
 			}
 		}
 		else if(bl->type == BL_PET) {
@@ -2007,6 +2010,8 @@ int status_get_hit(struct block_list *bl)
 				sc_data[SC_GOSPEL].val4 == BCT_PARTY &&
 				sc_data[SC_GOSPEL].val3 == 14)
 				hit += hit*5/100;
+			if(sc_data[SC_EXPLOSIONSPIRITS].timer!=-1)
+				hit += 20*sc_data[SC_EXPLOSIONSPIRITS].val1;
 		}
 	}
 	if(hit < 1) hit = 1;
@@ -2130,6 +2135,10 @@ int status_get_atk(struct block_list *bl)
 				atk -= atk*25/100;
 			if(sc_data[SC_CONCENTRATION].timer!=-1) //コンセントレーション
 				atk += atk*(5*sc_data[SC_CONCENTRATION].val1)/100;
+			if(sc_data[SC_EXPLOSIONSPIRITS].timer!=-1)
+				atk += (1000*sc_data[SC_EXPLOSIONSPIRITS].val1);
+			if(sc_data[SC_STRIPWEAPON].timer!=-1)
+				atk -= atk*10/100;
 
 			if(sc_data[SC_GOSPEL].timer!=-1) {
 				if (sc_data[SC_GOSPEL].val4 == BCT_PARTY &&
@@ -2191,6 +2200,8 @@ int status_get_atk2(struct block_list *bl)
 				atk2 = atk2*sc_data[SC_STRIPWEAPON].val2/100;
 			if(sc_data[SC_CONCENTRATION].timer!=-1) //コンセントレーション
 				atk2 += atk2*(5*sc_data[SC_CONCENTRATION].val1)/100;
+			if(sc_data[SC_EXPLOSIONSPIRITS].timer!=-1)
+				atk2 += (1000*sc_data[SC_EXPLOSIONSPIRITS].val1);
 		}
 		if(atk2 < 0) atk2 = 0;
 		return atk2;
@@ -2471,8 +2482,11 @@ int status_get_speed(struct block_list *bl)
 
 		if(sc_data) {
 			//速度増加時は25%減算
-			if(sc_data[SC_INCREASEAGI].timer!=-1 && sc_data[SC_DONTFORGETME].timer == -1)
+			if(sc_data[SC_INCREASEAGI].timer!=-1)
 				speed -= speed*25/100;
+			//ウィンドウォーク時はLv*2%減算
+			else if(sc_data[SC_WINDWALK].timer!=-1)
+				speed -= (speed*(sc_data[SC_WINDWALK].val1*2))/100;
 			//速度減少時は25%加算
 			if(sc_data[SC_DECREASEAGI].timer!=-1)
 				speed = speed*125/100;
@@ -2495,9 +2509,6 @@ int status_get_speed(struct block_list *bl)
 			//呪い時は450加算
 			if(sc_data[SC_CURSE].timer!=-1)
 				speed = speed + 450;
-			//ウィンドウォーク時はLv*2%減算
-			if(sc_data[SC_WINDWALK].timer!=-1 && sc_data[SC_INCREASEAGI].timer==-1)
-				speed -= (speed*(sc_data[SC_WINDWALK].val1*2))/100;
 			if(sc_data[SC_SLOWDOWN].timer!=-1)
 				speed = speed*150/100;
 			if(sc_data[SC_SPEEDUP0].timer!=-1)
@@ -3050,6 +3061,13 @@ int status_change_start(struct block_list *bl,int type,int val1,int val2,int val
 	if(type==SC_FREEZE && undead_flag && !(flag&1))
 		return 0;
 
+	if (type==SC_BLESSING && (bl->type==BL_PC || (!undead_flag && race!=6))) {
+		if (sc_data[SC_CURSE].timer!=-1)
+			status_change_end(bl,SC_CURSE,-1);
+		if (sc_data[SC_STONE].timer!=-1 && sc_data[SC_STONE].val2==0)
+			status_change_end(bl,SC_STONE,-1);
+	}
+
 	if((type == SC_ADRENALINE || type == SC_WEAPONPERFECTION || type == SC_OVERTHRUST) &&
 		sc_data[type].timer != -1 && sc_data[type].val2 && !val2)
 		return 0;
@@ -3066,15 +3084,25 @@ int status_change_start(struct block_list *bl,int type,int val1,int val2,int val
 	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_SPEEDPOTION3
-						 && type != SC_ATKPOT && type != SC_MATKPOT) // added atk and matk potions [Valaris]
+			&& type != SC_ATKPOT && type != SC_MATKPOT) // added atk and matk potions [Valaris]
 			return 0;
+
 		if ((type >=SC_STAN && type <= SC_BLIND) || type == SC_DPOISON)
 			return 0;/* ?ぎ足しができない?態異常である時は?態異常を行わない */
+
 		(*sc_count)--;
 		delete_timer(sc_data[type].timer, status_change_timer);
 		sc_data[type].timer = -1;
 	}
 
+	// クアグマイア/私を忘れないで中は無効なスキル
+	if ((sc_data[SC_QUAGMIRE].timer!=-1 || sc_data[SC_DONTFORGETME].timer!=-1) &&
+		(type==SC_CONCENTRATE || type==SC_INCREASEAGI ||
+		type==SC_TWOHANDQUICKEN || type==SC_SPEARSQUICKEN ||
+		type==SC_ADRENALINE || type==SC_LOUD || type==SC_TRUESIGHT ||
+		type==SC_WINDWALK || type==SC_CARTBOOST || type==SC_ASSNCROS))
+	return 0;
+
 	switch(type){	/* 異常の種類ごとの?理 */
 		case SC_PROVOKE:			/* プロボック */
 			calc_flag = 1;
@@ -3093,23 +3121,13 @@ int status_change_start(struct block_list *bl,int type,int val1,int val2,int val
 					status_change_start(bl,SC_PROVOKE,10,1,0,0,0,0);
 			}
 			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 )
-						status_change_end(bl,SC_CURSE,-1);
-					if(sc_data[SC_STONE].timer!=-1 && sc_data[SC_STONE].val2 == 0)
-						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 )
@@ -3151,16 +3169,21 @@ int status_change_start(struct block_list *bl,int type,int val1,int val2,int val
 		case SC_ADRENALINE:			/* アドレナリンラッシュ */
 			if(sc_data[SC_DECREASEAGI].timer!=-1)
 				return 0;
+			if(bl->type == BL_PC)
+				if(pc_checkskill(sd,BS_HILTBINDING)>0)
+					tick *= 1.1;
 			calc_flag = 1;
 			break;
 		case SC_WEAPONPERFECTION:	/* ウェポンパ?フェクション */
-			// Lasting time penalties have been removed on sakray as of 12/14 [celest]
-			//if(battle_config.party_skill_penalty && !val2) tick /= 5;
+			if(bl->type == BL_PC)
+				if(pc_checkskill(sd,BS_HILTBINDING)>0)
+					tick *= 1.1;
 			break;
 		case SC_OVERTHRUST:			/* オ?バ?スラスト */
+			if(bl->type == BL_PC)
+				if(pc_checkskill(sd,BS_HILTBINDING)>0)
+					tick *= 1.1;
 			*opt3 |= 2;
-			// Lasting time penalties have been removed on sakray as of 12/14 [celest]
-			//if(battle_config.party_skill_penalty && !val2) tick /= 10;
 			break;
 		case SC_MAXIMIZEPOWER:		/* マキシマイズパワ?(SPが1減る時間,val2にも) */
 			if(bl->type == BL_PC)
@@ -3624,10 +3647,9 @@ int status_change_start(struct block_list *bl,int type,int val1,int val2,int val
 			break;
 
 		case SC_TENSIONRELAX:	/* テンションリラックス */
-			calc_flag = 1;
 			if(bl->type == BL_PC) {
 				tick = 10000;
-			}
+			} else return 0;
 			break;
 
 		case SC_AURABLADE:		/* オ?ラブレ?ド */
@@ -3746,7 +3768,7 @@ int status_change_start(struct block_list *bl,int type,int val1,int val2,int val
 			break;
 
 		case SC_MEMORIZE:		/* メモライズ */
-			val2 = 3; //3回詠唱を1/3にする
+			val2 = 5; //回詠唱を1/3にする
 			break;
 
 		case SC_SPLASHER:		/* ベナムスプラッシャ? */
@@ -4001,10 +4023,7 @@ int status_change_end( struct block_list* bl , int type,int tid )
 			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:		/* トゥル?サイト */
@@ -4015,6 +4034,7 @@ int status_change_end( struct block_list* bl , int type,int tid )
 			case SC_MATKPOT:		/* magic attack potion [Valaris] */
 			case SC_WEDDING:	//結婚用(結婚衣裳になって?くのが?いとか)
 			case SC_MELTDOWN:		/* メルトダウン */
+			case SC_MINDBREAKER:		/* マインドブレーカー */
 			// Celest
 			case SC_EDP:
 			case SC_SLOWDOWN: