// ========================================= // PTvPT!! ver0.1 by某るし // ========================================= // ----------------------------------------- // 説明 // ----------------------------------------- /* Pvルールを使って、PT規模で勝利判定するゲームが 有ったら面白いんじゃないかと思って作成したものです。 控え室で参加パーティー登録後、ゲーム開始で全員を 指定マップに転送。いずれかのPTMemを残して他が全滅すると そこで勝利判定・転送をするルール。 恐らく罠は無いんじゃないかなと思いますが、結構無茶な処理 してると思われるので、完全に無いとは言い切れません。 有ったらごめんなさい。自分で抜いてください。 確か動作させてた環境はjAthena1446くらいだった気がします。 Athenaのスクリプトの書き方よくわからない状態から リファレンス見ながらスクリプト書き始めたので、配列の操作とか 一定していない部分が有って、非常に見苦しいですがご容赦を。 さらに、作成途中でサーバ自体の管理に飽きてしまい、スクリプトも 中途半端な仕上がりなので読みづらいかと思います。 晒すにあたって形成しなおそうかと思いましたが、もう自分でも よく覚えてなくてメンドウだったのでやめました。 鯖プログラム自体を弄らなくても、スクリプトだけでできる事の 一例程度の参考にしてもらえれば幸いです。 著作権みたいなものは特に主張しませんので、 煮るなり焼くなりご自由にどうぞ。 */ // ----------------------------------------- // 設置方法 // ----------------------------------------- /* 適当にこのスクリプトを読み込むように設置すればおk。 NPCのゲーム内での位置は適宜書き換えてください。 使用マップも適宜書き換えてください。 デフォのままだとpronteraに転送員、quiz_00を控え室、 pvp_n_1-1等をPTvPTマップとして使用しています。 コレだけでも機能するはずですが、デフォだとpvp_n_1-1.gat等は ナイトメアで装備落ちたり、リログでセーブポイントとかなので、 ↓マップフラグをこんな風に変えると幸せになれるかも pvp_n_1-1.gat mapflag nomemo dummy pvp_n_1-1.gat mapflag noteleport dummy pvp_n_1-1.gat mapflag nosave quiz_00.gat,115,115 pvp_n_1-1.gat mapflag pvp dummy pvp_n_1-1.gat mapflag pvp_noparty dummy pvp_n_1-1.gat mapflag pvp_nopenalty dummy マップを追加する方法については一番下あたりに少し書いた気がします。 デフォだと1マップしか存在しません。(定義してるだけで) マップセレクトの処理も、PTvPT開始役の処理ブロックに 追加する必要があります。 ルールの追加もそんなに難しくないと思われます。 コメント多めなので、何とか読み取ってやってください。 */ // ----------------------------------------- // 各種フラグ初期化用のマップイベント // ----------------------------------------- quiz_00.gat,0,0,0 script ptvptInit -1,{ end; OnInit: set $@ptvpt,0; //[メインフラグ]0:未開始 1:開始カウント中 2:戦闘中 set $@map_ptvpt$[0],"pvp_n_1-1.gat"; //[使用マップ1] set $@map_ptvpt$[1],"pvp_n_1-2.gat"; //[使用マップ2]未使用 set $@map_ptvpt$[2],"pvp_n_1-3.gat"; //[使用マップ3]未使用 set $@map_ptvpt$[3],"pvp_n_1-4.gat"; //[使用マップ4]未使用 set $@map_ptvpt$[4],"pvp_n_1-5.gat"; //[使用マップ5]未使用 set $@map_num,0; //[使用マップナンバー]1-5 set $@rule_ptvpt,0; //[ルール]0:ノーマルルール 1:MPKモード set $@entry_num,0; //[エントリーPT数] set $@start_num,4; //[スタート位置の候補数] //[開始座標設定]2元配列は使えないようなので…使用マップ*の(X,Y)=(pos*_x[i],pos*_y[i]) setarray $@start_pos0_x[0],157,70,39,116; setarray $@start_pos0_y[0],115,172,86,16; setarray $@start_pos1_x[0],123,76,64,135;//未使用 setarray $@start_pos1_y[0],76,123,135,64;//未使用 donpcevent "PTvPT転送要因::OnSet"; //入り口の人を初期化 end; } // ----------------------------------------- // 転送要員 // ----------------------------------------- prontera.gat,142,183,4 script PTvPT転送要員 105,{ mes "[PTvPT転送要員]"; mes "こちらからは、PTvPT控え室"; mes "への転送を行っています。"; next; menu "PTvPT控え室に行く",L_GO,"PTvPTって?",L_FAQ,"やめる",L_QUIT; L_GO: //PTvPT控え室へ if($@ptvpt==2){ mes "[PTvPT転送要員]"; mes "現在戦闘中ですので、"; mes "新規エントリーはできません。"; mes "それでもよろしいですか?"; next; menu "それでも行く",-,"やめる",L_QUIT; } mes "現在テスト版です。"; mes "正しく動作しない可能性があります!"; mes "あと、使用マップは5つになる予定です。"; next; //set $@in_num,$@in_num+1; //doevent "PTvPT転送要員::OnSet"; warp "quiz_00.gat",115,110; close; L_FAQ: //PTvPTの説明 mes "[PTvPT転送要員]"; mes "PTvPTとは、"; mes "パーティーvsパーティー"; mes "の略です。"; next; mes "[PTvPT転送要員]"; mes "最大4チームのパーティーで"; mes "戦闘を繰り広げることができます。"; next; mes "[PTvPT転送要員]"; mes "準備や方法などの詳しい事は、"; mes "PTvPT控え室の担当に"; mes "説明を受けてください。"; close; L_QUIT: //脱出 close; OnSet: //看板の更新イベント if($@ptvpt==0){ set $@temp$,"未開始"; }else if($@ptvpt==2){ set $@temp$,"戦闘中"; } waitingroom "PTvPT:状態["+$@temp$+"]",0; close; OnInit: //看板などの初期化イベント(必要なし:後で消すこと) set $@temp$,"未開始"; waitingroom "PTvPT:状態["+$@temp$+"]",0; end; } // 帰りの人 quiz_00.gat,114,105,0 script 転送要員 105,{ mes "[転送要員]"; mes "プロンテラに戻りますか?"; next; menu "戻る",L_GO,"戻らない",L_EXIT; L_GO: //memoアイテムなくす処理とか入れるならここ set $@in_num,$@in_num-1; warp "prontera.gat",156,191; close; L_END: close; } // ----------------------------------------- // PTvPT開始役 // ----------------------------------------- quiz_00.gat,115,136,4 script ガルソディ 734,{ //まずフラグで分岐 if($@ptvpt==1){ goto L_STARTING; //転送秒読み中 }else if($@ptvpt==2){ goto L_STARTED; //戦闘中 } //■通常の動作 mes "[ガルソディ]"; mes "ここはPTvPT受付だ。"; mes "何の用だ?"; next; menu "エントリーをする",L_ENTRY,"エントリーを取り消す",L_QUIT_ENTRY,"エントリーPTを確認",L_CHK,"ルールを変更する",L_RULE,"PTvPT開始",L_START,"設定のリセット",L_RESET,"やめる",L_QUIT; L_MENU: //メニュー mes "[ガルソディ]"; mes "他に何か用はあるか?"; next; menu "エントリーをする",L_ENTRY,"エントリーを取り消す",L_QUIT_ENTRY,"エントリーPTを確認",L_CHK,"ルールを変更する",L_RULE,"PTvPT開始",L_START,"設定のリセット",L_RESET,"やめる",L_QUIT; L_ENTRY://★エントリーをする if($@lock_ptvpt==1){ mes "[ガルソディ]"; mes "現在、他の誰かが利用中だ。"; mes "少々待ってくれ。"; next; goto L_MENU; } set $@lock_ptvpt,1; //お粗末な排他処理:ロックをかける //エントリー状態を確認 set @temp,getcharid(1); if($@entry_num==0) goto L_ENTRY2; //カウントが0ならば検索なしで追加 for(set @i,0;@i<$@entry_num;set @i,@i+1){ if($@entry_ptid[@i]==@temp) goto L_ENTRY_ERR; } goto L_ENTRY2; L_ENTRY_ERR: mes "[ガルソディ]"; mes "すでに君のパーティー"; mes "^0000EE"+getpartyname(@temp)+"^000000 は"; mes "エントリー済みのようだ。"; next; goto L_ENTRY_EXIT; L_ENTRY2: mes "[ガルソディ]"; mes "では君のパーティー"; mes "^0000EE"+getpartyname(@temp)+"^000000 の"; mes "エントリーを受け付けよう。"; mes "よいかね?"; next; menu "エントリーをする",L_ENTRY3,"やっぱりやめる",L_ENTRY_EXIT; L_ENTRY3: //エントリーを受け付ける set $@entry_ptid[$@entry_num],@temp; set $@entry_num,$@entry_num+1; mes "[ガルソディ]"; mes "確かにエントリーを受け付けた。"; next; L_ENTRY_EXIT: //エントリーから抜ける処理 set $@lock_ptvpt,0; goto L_MENU; L_QUIT_ENTRY://★エントリーを取り消す if($@lock_ptvpt==1){ mes "[ガルソディ]"; mes "現在、他の誰かが利用中だ。"; mes "少々待ってくれ。"; next; goto L_MENU; } set $@lock_ptvpt,1; //ロックをかける //エントリー状態を確認 set @temp,getcharid(1); if($@entry_num==0) goto L_QUIT_ENTRY_ERR; //カウントが0ならば即エラー for(set @i,0;@i<$@entry_num;set @i,@i+1){ if($@entry_ptid[@i]==@temp) goto L_QUIT_ENTRY2; } goto L_QUIT_ENTRY_ERR; L_QUIT_ENTRY_ERR: mes "[ガルソディ]"; mes "君のパーティーはエントリー"; mes "されていないようだ。"; next; goto L_QUIT_ENTRY_EXIT; L_QUIT_ENTRY2: mes "[ガルソディ]"; mes "では君のパーティー"; mes "^0000EE"+getpartyname(@temp)+"^000000 の"; mes "エントリーを取り消そう。"; mes "よいかね?"; next; menu "エントリーを取り消す",L_QUIT_ENTRY3,"やっぱりやめる",L_QUIT_ENTRY_EXIT; L_QUIT_ENTRY3: //エントリーを取り消し set $@entry_num,$@entry_num-1; for(set @i,@i;@i<$@entry_num;set @i,@i+1){ set $@entry_ptid[@i],$@entry_ptid[@i+1]; } mes "[ガルソディ]"; mes "エントリーを取り消したぞ。"; next; L_QUIT_ENTRY_EXIT: //クイットエントリーから抜ける処理 set $@lock_ptvpt,0; goto L_MENU; L_CHK: //★エントリーチェック //エントリーパーティーはいる? if($@entry_num==0){ mes "[ガルソディ]"; mes "現在エントリーしている"; mes "パーティーはないようだ。"; next; goto L_MENU; } mes "[ガルソディ]"; mes "現在エントリーしている"; mes "パーティーの情報は次のとおりだ。"; next; for(set @i,0;@i<$@entry_num;set @i,@i+1){ set @temp,$@entry_ptid[@i]; getpartymember(@temp); set @j,@i+1; mes @j+". ^0000EE"+getpartyname(@temp)+"^000000"; for(set @j,0;@j<$@partymembercount;set @j,@j+1){ mes $@partymembername$[@j]; } next; } goto L_MENU; L_RULE: //★ルール変更 mes "[ガルソディ]"; mes "まだ未実装だ。"; mes " "; mes "がんばってますっ"; mes "ごめんなさいっ人('A`)"; next; goto L_MENU; L_START://★PTvPTスタートです //エントリー数が2未満なら終了 if($@entry_num<2){ mes "[ガルソディ]"; mes "エントリーしているパーティーが"; mes "2つ以上じゃないと開始はできないぞ。"; next; goto L_MENU; } if($@lock_ptvpt==1){ mes "[ガルソディ]"; mes "現在、他の誰かが利用中だ。"; mes "少々待ってくれ。"; next; goto L_MENU; } set $@lock_ptvpt,1; //ロックをかける mes "[PTvPT転送要員]"; mes "現在エントリーしているパーティーは^0000EE"; for(set @i,0;@i<$@entry_num;set @i,@i+1){ set @temp,$@entry_ptid[@i]; mes getpartyname(@temp); } mes "^000000の"+$@entry_num+"つのパーティーだ。"; next; mes "[ガルソディ]"; mes "本当にPTvPTを開始してもいいんだな?"; mes "全員に了承はとったか?"; next; menu "PTvPT開始!!",L_START2,"ちょっとまって",L_START_EXIT; L_START2: set $@ptvpt,1; //フラグ変更 initnpctimer "StartTimer";//タイマー開始 set $@lock_ptvpt,0; close; L_START_EXIT: set $@lock_ptvpt,0; goto L_MENU; L_RESET://★設定のリセット mes "[ガルソディ]"; mes "設定のリセットをするか?"; mes "ロックがかかったままに"; mes "なってしまった場合や、"; mes "すべてやり直すときに使ってくれ。"; next; menu "リセットをする",L_RESET2,"やめる",L_MENU; L_RESET2: mes "[ガルソディ]"; mes "リセットしても本当にいいんだな?"; next; menu "いい",L_RESET3,"やめる",L_MENU; L_RESET3: set $@lock_ptvpt,0; set $@entry_num,0; mes "[ガルソディ]"; mes "リセットしたぞ。"; next; goto L_MENU; L_QUIT://★終了するところ close; //■カウント中 L_STARTING: mes "[ガルソディ]"; mes "開始を取りやめるか?"; menu "取りやめる",-,"やめない",L_QUIT; stopnpctimer "StartTimer"; announce "ガルソディ : 転送をキャンセルしたぞ。",0x01; set $@ptvpt,0; close; //■戦闘中 L_STARTED: mes "[ガルソディ]"; mes "現在中で^0000EE"; for(set @i,0;@i<$@entry_num;set @i,@i+1){ set @temp,$@entry_ptid[@i]; mes @temp; } mes "の"+$@entry_num+"パーティーが戦闘中だ。"; next; mes "[ガルソディ]"; mes "終了するまでしばらく待ってくれ。"; close; //■初期化イベント OnInit: set $@entry_num,0; set $@lock,0; donpcevent "PTvPT転送要因::OnSet"; } // ----------------------------------------- // PTvPT転送イベント // ----------------------------------------- quiz_00.gat,0,0,0 script StartTimer -1,{ end; OnTimer200: mapannounce "quiz_00.gat","ガルソディ : では、これより5秒後に転送を開始する。",8; mapannounce "quiz_00.gat","ガルソディ : 取り消したい場合は5秒以内に私に話しかけるように。",8; end; OnTimer1200: mapannounce "quiz_00.gat","ガルソディ : 4秒前",8; end; OnTimer2200: mapannounce "quiz_00.gat","ガルソディ : 3秒前",8; end; OnTimer3200: mapannounce "quiz_00.gat","ガルソディ : 2秒前",8; end; OnTimer4200: mapannounce "quiz_00.gat","ガルソディ : 1秒前",8; end; OnTimer5200://★転送開始 set $@ptvpt,2; donpcevent "PTvPT転送要因::OnSet"; //ジャンプ先の座標をコピー(2元配列がないとこうするしか…) switch($@map_num){ case 0: copyarray $@jump_x[0],$@start_pos0_x[0],$@start_num; copyarray $@jump_y[0],$@start_pos0_y[0],$@start_num; break; default: break; } //すげー適当なシャッフル(開始地点候補が多くなればなるほどシャッフル数を多くしないとダメ) for(set $@j,0;$@j<10;set $@j,$@j+1){ set $@temp_1,rand($@start_num); set $@temp_2,rand($@start_num); set $@temp,$@jump_x[$@temp_1]; set $@jump_x[$@temp_1],$@jump_x[$@temp_2]; set $@jump_x[$@temp_2],$@temp; set $@temp,$@jump_y[$@temp_1]; set $@jump_y[$@temp_1],$@jump_y[$@temp_2]; set $@jump_y[$@temp_2],$@temp; } //パーティーごとに転送開始 for(set $@i,0;$@i<$@entry_num;set $@i,$@i+1){ set $@temp,$@entry_ptid[$@i]; getpartymember($@temp); for(set $@j,0;$@j<$@partymembercount;set $@j,$@j+1){ //一人一人飛ばしていく if(attachrid(getcharid(3,$@partymembername$[$@j]))!=0){ //たぶんここで控え室にいるかの判定も入れるべき warp $@map_ptvpt$[$@map_num],$@jump_x[$@i],$@jump_y[$@i]; detachrid; } } } initnpctimer "GameStart"; end; } // ----------------------------------------- // 解説役 // ----------------------------------------- quiz_00.gat,112,129,4 script ユルト 728,{ mes "[ユルト]"; mes "こんにちは、PTvPT"; mes "解説役のユルトですっ!"; next; menu "PTvPTって?",L_0,"開始方法は?",L_1,"ルールについて教えて!",L_2,"用はない。",L_END1; L_MENU: next; menu "PTvPTって?",L_0,"開始方法は?",L_1,"ルールについて教えて!",L_2,"もう聞くことはない。",L_END2; L_0: //PTvPTって? mes "[ユルト]"; mes "PTvPTとは、"; mes "パーティーvsパーティーの略で"; mes "エリア内の他PTを排除する"; mes "ゲームの事です。"; next; mes "[ユルト]"; mes "PTvPTには、最大4PTが同時に"; mes "参加することができ、"; mes "3PT以上のゲームだと、他のPTを"; mes "すべて潰すバトルロイヤル形式と"; mes "なります。"; next; mes "[ユルト]"; mes "PTvPTは、専用のマップで行います。"; mes "東西南北4つの開始地点から、"; mes "それぞれのPTの開始地点が"; mes "ランダムに決定されます。"; next; mes "[ユルト]"; mes "専用マップは、PVPのルールに"; mes "設定されています。"; mes "専用マップに転送された直後から"; mes "ゲーム開始となります。"; next; mes "[ユルト]"; mes "頑張って他のパーティーを"; mes "虐殺してください♪"; goto L_MENU; L_1: //開始方法は? mes "[ユルト]"; mes "開始方法は重要です!"; mes "PTメンバー皆さんが確認して"; mes "おいたほうが良いですよ〜。"; next; mes "[ユルト]"; mes "まず、PTを用意してください。"; mes "初めから用意されていたものでも、"; mes "ここで作成するものでも良いです。"; mes "PTに入っていない人は、"; mes "ゲームに参加できません!"; next; mes "[ユルト]"; mes "次に、中央のガルソディに"; mes "話しかけて、パーティーの"; mes "エントリーを行います。"; next; mes "[ユルト]"; mes "エントリーはPTメンバーの"; mes "誰か一人が行えばそれで終了です。"; next; mes "[ユルト]"; mes "注意)"; mes "エントリーするPTは、ここにいる"; mes "メンバーのみで構成されたPTと"; mes "してください。"; mes "外部にいるメンバーも強制的に"; mes "参加させようとしてしまいます!"; next; mes "[ユルト]"; mes "すべての参加するPTがエントリーを"; mes "終了させ、ルールも決定していたら、"; mes "誰でも良いので、ガルソディに話かけ"; mes "開始を選んでください。"; next; mes "[ユルト]"; mes "5秒後に、すべてのPTのメンバーが"; mes "転送されて、ゲーム開始となります。"; goto L_MENU; L_2: //ルールについて教えて! mes "[ユルト]"; mes "■ノーマルモード"; mes "通常のモードです。"; mes "マップルールはPvP。"; mes "相手を全滅させれば勝利です。"; next; mes "[ユルト]"; mes "■MPKモード"; mes "マップルールはPvPで、相手を全滅"; mes "させれば勝利というルールは、"; mes "ノーマルモードと変わりません。"; next; mes "[ユルト]"; mes "ですが、ここでは一定時間で"; mes "MVPBOSSが沸きます。"; mes "出てきたMVPをうまく相手に向けることで"; mes "戦略の幅が広がります。"; goto L_MENU; L_END1: mes "[ユルト]"; mes "自分の存在意義に悩む、"; mes "今日この頃です…"; close; L_END2: mes "[ユルト]"; mes "またわからないことがあったら"; mes "何でも聞いてくださいね。"; close; } // ----------------------------------------- // ゲームの状況を管理するマップイベント // ----------------------------------------- - script GameStart -1,{ end; OnTimer5000: //変数などの初期化 set $@exist_num,$@entry_num; copyarray $@exist_ptid,$@entry_ptid,$@entry_num; //スタートのアナウンス・生存チェック開始 mapannounce $@map_ptvpt$[$@map_num],"PTvPTスタート!!",8; initnpctimer "GameMaster"; end; } - script GameMaster -1,{ end; OnTimer5000: //5秒ごとに生存チェックをかける //エントリーメンバーすべての所在とHPを確認(おもそー(´Д`;)) for(set $@i,0;$@i<$@exist_num;set $@i,$@i+1){ set $@check_flag,0; set $@temp,$@exist_ptid[$@i]; getpartymember($@temp); for(set $@j,0;$@j<$@partymembercount;set $@j,$@j+1){ if(attachrid(getcharid(3,$@partymembername$[$@j]))){ //マップが違えばだめよ if(getmapname($@partymembername$[$@j])==$@map_ptvpt$[$@map_num]){ //HPがちゃんとまだある? if(HP>0){ set $@check_flag,1; break; } } } } //ここにきてcheck_flagが0なら全滅している if($@check_flag==0){ mapannounce $@map_ptvpt$[$@map_num],"パーティー["+getpartyname($@temp)+"]が全滅しました!",8; set $@exist_num,$@exist_num-1; deletearray $@exist_ptid[$@i],1; } } //まだゲームが続くか? if($@exist_num==1){ //ただ1PTの勝利 mapannounce $@map_ptvpt$[$@map_num],"おめでとうございます、パーティー["+getpartyname($@exist_ptid[0])+"]の勝利です!",8; goto L_EXIT; }else if($@exist_ptid==0){ //相打ち mapannounce $@map_ptvpt$[$@map_num],"同時に全滅しました!引き分けです!",8; goto L_EXIT; } initnpctimer; //自分のタイマーをInit end; L_EXIT: //★すべてのキャラクターを排除して終了 initnpctimer "GameQuit"; stopnpctimer; end; } - script GameQuit -1,{ end; OnTimer5000: //残ってる人は強制的に全員復活させる(誰でもいいから適当にアタッチしないとGMコマンド使えない) for(set $@i,0;$@i<$@entry_num;set $@i,$@i+1){ set $@temp,$@entry_ptid[$@i]; getpartymember($@temp); for(set $@j,0;$@j<$@partymembercount;set $@j,$@j+1){ if(attachrid(getcharid(3,$@partymembername$[$@j]))!=0){ //マップが違えばだめよ if(getmapname($@partymembername$[$@j])==$@map_ptvpt$[$@map_num]){ gmcommand "@raisemap"; break; } } } } //★すべてのキャラクターを排除して終了(範囲座標は全部になるっぽく適当) areawarp $@map_ptvpt$[$@map_num],0,0,999,999,"quiz_00.gat",115,115; donpcevent "ptvptInit::OnInit"; end; } // duplicateで複製して、楽に対応マップ増やせないかなと思ったけど、どうも無理な感じ…?@jAthena1446 // なので、対応マップ増やすにはGameStart・GameMaster・GameQuitのブロックを増やしたいだけコピーして // gatの名前をそれぞれ手作業で変えるしかないかな? // ↑のそれぞれのブロックを適宜変更して↓こんな風にしてもダメだった。 //pvp_n_1-1.gat,0,0,0 duplicate(GameStart) GameStart -1 //pvp_n_1-1.gat,0,0,0 duplicate(GameMaster) GameMaster -1 //pvp_n_1-1.gat,0,0,0 duplicate(GameQuit) GameQuit -1 //pvp_n_1-2.gat,0,0,0 duplicate(GameStart) GameStart -1 //...