//Tut instance by Skorm 12/26/2014 //Inside Server Files in db quest_db.txt add: //Instance Cooldown Time Limit in seconds //80008,604800,0,0,0,0,0,0,"New Instance" //" Comments (Tutorial Part #1) //Basically these two commented out parts act as the cooldown time for your instance... //80008 - in the segment above is the quest ID. //604800 - is the delay is seconds that the player may retake the quest. //0,0,0,0,0,0 - this part you can pretty much ignore it's just item/mob ids that the quest would normally accept but here we're just using it as a time to make things simple which also saves from us having to deal with it in the script. //"New Instance" - This is the name that will be displayed for our quest in the quest_db. //" //Inside Custom GRF in questid2display.txt add: //80008#New Instance#SG_FEEL#QUE_NOIMAGE# //You've talked to the mysterious guard and he's warped you to an ancient land.# //Defeat the dreaded Poringz0rd!# //" Comments (Tutorial Part #2) //80008 - Again we can see this acts as the quest ID. We'll use this later to give the character our quest. //New Instance - This is the name of our quest this will show up for the client and should be the same as in quest_db. //SG_FEEL - This is the small icon that will appear for the quest in the players quest log. //QUE_NOIMAGE - This is a bigger image that is displayed when the player clicks on the quest in his or her log. //You've talked to the mysterious guard and he's warped you to an ancient land. - This is a description of the quest. //Defeat the dreaded Poringz0rd! - This is the quest objective. //" //Inside Server Files in db instance_db.txt add: //13,New Instance,14400,1@abys,116,25,1@abys,2@abys,3@abys,4@abys,5@abys //" Comments (Tutorial Part #3) //This is the main instance npc (he is going to handle most of the real-time events). //1@abys,0,0,0 - You probably already know this one but... map,x,y,direction... We'll get to why they are mostly zero in a second. // - This is a tab and is needed to space the npc header. //script - This just tells the phaser what the npc is... either script, function, or shop. //Time_Keep - This is the npc name that shows up when you hover over the npc with your mouse. //-1 - This is why we don't have any coordinates in the first option. Setting this to -1 means the npc won't show up on the map or have a sprite... Normally these are the npc sprite numbers. // {- this is a curly and encases the parts of this script that we want to use for this npc. //" 1@abys,0,0,0 script Time_Keep -1,{ // This is a function bascially functions are just bits of code that I can call from other parts of the script send information to and then return to where I was before. // Currently this function just spawns new monsters in the area i'd like and with the label I want. function area_monster { areamonster instance_mapname(getarg(0)),getarg(2,0),getarg(3,0),getarg(4,0),getarg(5,0),getarg(8,"--ja--"),getarg(1),getarg(6,1),instance_npcname("Time_Keep")+"::"+getarg(7); return; } // This is a label. Labels can be called like functions but I can't send information to the label in a conventional matter, but labels are often faster than functions. // The label is used for the reward when the player finishes the instance. OnReward: //addrid(2,0,.party_id); set(Zeny,Zeny+.zeny); callfunc("package_func",512,1,100,getcharid(3)); end; // This label is attached to my spawned mobs whenever a mob is killed the instance variable 'mob is increased by 1. OnMob: 'mob++; end; // This is a special label I made to show players when and where warps open up on the minimap. SubSetView: getpartymember getarg(2),1; getpartymember getarg(2),2; set .@plen, $@partymembercount; for( .@i = 0; .@i < .@plen; .@i++ ) { if( isloggedin( $@partymemberaid[.@i], $@partymembercid[.@i] ) ) { attachrid( $@partymemberaid[.@i] ); viewpoint 1,getarg(0),getarg(1),1,0xFF0000; detachrid; } } return; //Room 01 //"map", "mobid", "x1", "y1", "x2", "y2", "amount", "trigger"; // OnInstanceInit is a special label that is called whenever the instance is started. OnInstanceInit: // this command just sends information to the server concole. debugmes "Instance Created! "+'party_id; //93, 112, 106, 98 middle area // Here you can see I've used the function to create a monster with the label OnMob01_0. area_monster ( "1@abys", 1002, 53, 165, 172, 42, 20, "OnMob01_0" ); end; OnMob01_0: // Here I've used a special command. The command I've used mobcount searches the map for the existing mobs above with the OnMob01_0. // If this command which is called every time a monster is killed realizes that no more mobs exist it will allow the script to pass through. // Thus summoning more monsters. if( !mobcount( instance_mapname("1@abys"), instance_npcname("Time_Keep")+"::OnMob01_0" ) ) area_monster( "1@abys", 1002, 53, 165, 172, 42, 20, "OnMob01_1" ); end; // I continue this pattern for the remainder of the script. OnMob01_1: if( !mobcount( instance_mapname("1@abys"), instance_npcname("Time_Keep")+"::OnMob01_1" ) ) area_monster( "1@abys", 1002, 53, 165, 172, 42, 20, "OnMob01_2" ); end; OnMob01_2: if( !mobcount( instance_mapname("1@abys"), instance_npcname("Time_Keep")+"::OnMob01_2" ) ) area_monster( "1@abys", 1002, 53, 165, 172, 42, 20, "OnMob01_3" ); end; OnMob01_3: if( !mobcount( instance_mapname("1@abys"), instance_npcname("Time_Keep")+"::OnMob01_3" ) ) area_monster( "1@abys", 1002, 53, 165, 172, 42, 20, "OnMob01_4" ); end; OnMob01_4: if( !mobcount( instance_mapname("1@abys"), instance_npcname("Time_Keep")+"::OnMob01_4" ) ) area_monster( "1@abys", 1002, 53, 165, 172, 42, 1, "OnMob01_5" ); end; //======= //Room 02 OnMob01_5: if( !mobcount( instance_mapname("1@abys"), instance_npcname("Time_Keep")+"::OnMob01_5" ) ) { // You can see here things start to change a little. // This command enables an npc that was previously disabled. // This npc just happens to be a warp. enablenpc instance_npcname("warper#1-2"); // here I use a command to obtain the location of said npc. getmapxy(.@map$,.@x,.@y,1,instance_npcname("warper#1-2")); // here I call the previous label like a function but instead with the sub command. // This allows me to retain information like the instance variables. callsub SubSetView, .@x, .@y, 'party_id; area_monster( "2@abys", 1002, 53, 165, 172, 42, 20, "OnMob02_0" ); } end; OnMob02_0: if( !mobcount( instance_mapname("2@abys"), instance_npcname("Time_Keep")+"::OnMob02_0" ) ) area_monster( "2@abys", 1002, 53, 165, 172, 42, 20, "OnMob02_1" ); end; OnMob02_1: if( !mobcount( instance_mapname("2@abys"), instance_npcname("Time_Keep")+"::OnMob02_1" ) ) area_monster( "2@abys", 1002, 53, 165, 172, 42, 20, "OnMob02_2" ); end; OnMob02_2: if( !mobcount( instance_mapname("2@abys"), instance_npcname("Time_Keep")+"::OnMob02_2" ) ) area_monster( "2@abys", 1002, 53, 165, 172, 42, 20, "OnMob02_3" ); end; OnMob02_3: if( !mobcount( instance_mapname("2@abys"), instance_npcname("Time_Keep")+"::OnMob02_3" ) ) area_monster( "2@abys", 1002, 53, 165, 172, 42, 20, "OnMob02_4" ); end; OnMob02_4: if( !mobcount( instance_mapname("2@abys"), instance_npcname("Time_Keep")+"::OnMob02_4" ) ) area_monster( "2@abys", 1002, 53, 165, 172, 42, 1, "OnMob02_5" ); end; //======== //Room 03.1 OnMob02_5: if( !mobcount( instance_mapname("2@abys"), instance_npcname("Time_Keep")+"::OnMob02_5" ) ) { // I've done the exact same thing to open up another warp. enablenpc instance_npcname("warper#2-3"); getmapxy(.@map$,.@x,.@y,1,instance_npcname("warper#2-3")); callsub SubSetView, .@x, .@y, 'party_id; area_monster( "3@abys", 1002, 53, 165, 172, 42, 20, "OnMob03_1_0" ); } end; OnMob03_1_0: if( !mobcount( instance_mapname("3@abys"), instance_npcname("Time_Keep")+"::OnMob03_1_0" ) ) area_monster( "3@abys", 1002, 53, 165, 172, 42, 20, "OnMob03_1_1" ); end; OnMob03_1_1: if( !mobcount( instance_mapname("3@abys"), instance_npcname("Time_Keep")+"::OnMob03_1_1" ) ) area_monster( "3@abys", 1002, 53, 165, 172, 42, 20, "OnMob03_1_2" ); end; OnMob03_1_2: if( !mobcount( instance_mapname("3@abys"), instance_npcname("Time_Keep")+"::OnMob03_1_2" ) ) area_monster( "3@abys", 1002, 53, 165, 172, 42, 20, "OnMob03_1_3" ); end; OnMob03_1_3: if( !mobcount( instance_mapname("3@abys"), instance_npcname("Time_Keep")+"::OnMob03_1_3" ) ) area_monster( "3@abys", 1002, 53, 165, 172, 42, 20, "OnMob03_1_4" ); end; OnMob03_1_4: if( !mobcount( instance_mapname("3@abys"), instance_npcname("Time_Keep")+"::OnMob03_1_4" ) ) area_monster( "3@abys", 1002, 53, 165, 172, 42, 1, "OnMob03_1_5" ); end; //========= //Room 02 - Part 2 OnMob03_1_5: if( !mobcount( instance_mapname("3@abys"), instance_npcname("Time_Keep")+"::OnMob03_1_5" ) ) { enablenpc instance_npcname("warper#3-2"); getmapxy(.@map$,.@x,.@y,1,instance_npcname("warper#3-2")); callsub SubSetView, .@x, .@y, 'party_id; // Here I'm using the command rand(101) random 101 will return a value between 0 ~ 100 and random. // If random is less than 1 so 0 it will spawn a chest. (1% probability) if( rand(101) < 1 ) { // 1 in 100 chance of spawning a treasure box. instance_announce -1,"A Treasure chest has spawned!",bc_blue; area_monster( "3@abys", 1332, 93, 112, 106, 98, 1, "OnMob" ); } area_monster( "2@abys", 1002, 53, 165, 172, 42, 20, "OnMob02_2_0" ); } end; OnMob02_2_0: if( !mobcount( instance_mapname("2@abys"), instance_npcname("Time_Keep")+"::OnMob02_2_0" ) ) area_monster( "2@abys", 1002, 53, 165, 172, 42, 20, "OnMob02_2_1" ); end; OnMob02_2_1: if( !mobcount( instance_mapname("2@abys"), instance_npcname("Time_Keep")+"::OnMob02_2_1" ) ) area_monster( "2@abys", 1002, 53, 165, 172, 42, 20, "OnMob02_2_2" ); end; OnMob02_2_2: if( !mobcount( instance_mapname("2@abys"), instance_npcname("Time_Keep")+"::OnMob02_2_2" ) ) area_monster( "2@abys", 1002, 53, 165, 172, 42, 20, "OnMob02_2_3" ); end; OnMob02_2_3: if( !mobcount( instance_mapname("2@abys"), instance_npcname("Time_Keep")+"::OnMob02_2_3" ) ) area_monster( "2@abys", 1002, 53, 165, 172, 42, 20, "OnMob02_2_4" ); end; OnMob02_2_4: if( !mobcount( instance_mapname("2@abys"), instance_npcname("Time_Keep")+"::OnMob02_2_4" ) ) area_monster( "2@abys", 1002, 53, 165, 172, 42, 1, "OnMob02_2_5" ); end; //======== //Room 03.2 OnMob02_2_5: if( !mobcount( instance_mapname("2@abys"), instance_npcname("Time_Keep")+"::OnMob02_2_5" ) ) { enablenpc instance_npcname("warper#2-4"); getmapxy(.@map$,.@x,.@y,1,instance_npcname("warper#2-4")); callsub SubSetView, .@x, .@y, 'party_id; area_monster( "4@abys", 1002, 53, 165, 172, 42, 20, "OnMob03_2_0" ); } end; OnMob03_2_0: //Type 1... if( !mobcount( instance_mapname("4@abys"), instance_npcname("Time_Keep")+"::OnMob03_2_0" ) ) area_monster( "4@abys", 1002, 53, 165, 172, 42, 20, "OnMob03_2_1" ); end; OnMob03_2_1: //Type 2... if( !mobcount( instance_mapname("4@abys"), instance_npcname("Time_Keep")+"::OnMob03_2_1" ) ) area_monster( "4@abys", 1002, 53, 165, 172, 42, 20, "OnMob03_2_2" ); end; OnMob03_2_2: //Type 3... if( !mobcount( instance_mapname("4@abys"), instance_npcname("Time_Keep")+"::OnMob03_2_2" ) ) area_monster( "4@abys", 1002, 53, 165, 172, 42, 1, "OnMob03_2_3" ); end; OnMob03_2_3: //Type 3... if( !mobcount( instance_mapname("4@abys"), instance_npcname("Time_Keep")+"::OnMob03_2_3" ) ) area_monster( "4@abys", 1002, 53, 165, 172, 42, 1, "OnMob03_2_4" ); end; OnMob03_2_4: //Type 3... if( !mobcount( instance_mapname("4@abys"), instance_npcname("Time_Keep")+"::OnMob03_2_4" ) ) area_monster( "4@abys", 1002, 53, 165, 172, 42, 1, "OnMob03_2_5" ); end; //Room 03.2 - Part 2 OnMob03_2_5: //MVP if( !mobcount( instance_mapname("4@abys"), instance_npcname("Time_Keep")+"::OnMob03_2_5" ) ) { // Here I've used the instance_announce command to announce to the instance map. instance_announce -1,"The Summoner has been summoned!",bc_map,"0x00ff99"; // Also if you look here you can see that I'm enabling an npc this time around instead of a warp. enablenpc instance_npcname("Summoner#1"); getmapxy(.@map$,.@x,.@y,1,instance_npcname("Summoner#1")); callsub SubSetView, .@x, .@y, 'party_id; } end; //========== //Nest OnMob03_2_2_1: if( !mobcount( instance_mapname("4@abys"), instance_npcname("Time_Keep")+"::OnMob03_2_2_1" ) ) { enablenpc instance_npcname("warper#4-5"); getmapxy(.@map$,.@x,.@y,1,instance_npcname("warper#4-5")); callsub SubSetView, .@x, .@y, 'party_id; area_monster( "5@abys", 1002, 93, 112, 106, 98, 1, "OnMobNest" ); //MVP } end; //==== OnMobNest: if( !mobcount( instance_mapname("5@abys"), instance_npcname("Time_Keep")+"::OnMobNest" ) ) { enablenpc instance_npcname("item_create_npc#1"); getmapxy(.@map$,.@x,.@y,1,instance_npcname("item_create_npc#1")); callsub SubSetView, .@x, .@y, 'party_id; instance_announce -1,"Congratulations an item creating npc has spawned in the middle of the map!",bc_yellow; } end; } // Here you'll find all the warp npcs.... 1@abys,149,161,3 script warper#1-2 45,2,2,{ OnTouch: warp instance_mapname("2@abys"),116,25; end; OnInstanceInit: disablenpc instance_npcname("warper#1-2"); } 2@abys,61,170,3 script warper#2-3 45,2,2,{ OnTouch: warp instance_mapname("3@abys"),116,32; end; OnInstanceInit: disablenpc instance_npcname("warper#2-3"); } 3@abys,116,25,3 script warper#3-2 45,2,2,{ OnTouch: warp instance_mapname("2@abys"),63,164; end; OnInstanceInit: disablenpc instance_npcname("warper#3-2"); } 2@abys,149,161,3 script warper#2-4 45,2,2,{ OnTouch: warp instance_mapname("4@abys"),116,25; end; OnInstanceInit: disablenpc instance_npcname("warper#2-4"); } 4@abys,98,104,3 script warper#4-5 45,2,2,{ OnTouch: warp instance_mapname("5@abys"),98,104; end; OnInstanceInit: disablenpc instance_npcname("warper#4-5"); } // These are the npcs I've enabled throughout the instance. 4@abys,92,110,3 script Summoner#1 100,{ function area_monster { areamonster instance_mapname(getarg(0)),getarg(2,0),getarg(3,0),getarg(4,0),getarg(5,0),getarg(8,"--ja--"),getarg(1),getarg(6,1),instance_npcname("Time_Keep")+"::"+getarg(7); return; } if( getpartyleader( getcharid(1), 2 ) == getcharid(0) ) { mes "[ Summoner ]"; mes "You should not do this!"; mes "The highness is sleeping!"; next; select( "The Dragon must be gone!" ); mes "[ Summoner ]"; mes "You mortal!"; mes "Ktulls! Detals! Kill him!!!"; area_monster( "4@abys", 1002, 53, 165, 172, 42, 3, "OnMob03_2_2_1" ); //Detal x3 area_monster( "4@abys", 1002, 53, 165, 172, 42, 3, "OnMob03_2_2_1" ); //Ktallnalux x3 disablenpc instance_npcname("Summoner#1"); close; } else { mes "[ Summoner ]"; mes "I'll only talk to your leader!"; close; } end; OnInstanceInit: disablenpc instance_npcname("Summoner#1"); } 5@abys,98,104,3 script item_create_npc#1 100,{ mes "[ place holder ]"; if ( select("I'm staying...:I'd like to warp out.") == 2 ) { warp "prontera",156,191; end; } close; end; OnInstanceInit: disablenpc instance_npcname("item_create_npc#1"); } /// callfunc("package_func",,,{,,,{,,,{,...},}}) function script package_func { set .@len, getargcount()-((getarg(getargcount()-1)>=2000000)?1:0); set .@id, ((getarg(getargcount()-1)>=2000000)?getarg(getargcount()-1):getcharid(3)); while(set(.@i,.@i+3)-3<.@len) if(rand(101)<=getarg(.@i-1)) getitem(set(@package_item[.@a++-1],getarg(.@i-3)),set(@package_amount[.@a-1],getarg(.@i-2)),.@id); return .@a; } 1@abys mapflag src4instance 2@abys mapflag src4instance 3@abys mapflag src4instance 4@abys mapflag src4instance 5@abys mapflag src4instance new_1-1,51,104,5 script Instance Enter 480,{ set .@party_id, getcharid( 1 ); // Set party ID. set .@playtime, checkquest( .cooldown, PLAYTIME ); // Set Cool-down variable... //Here I'm just cutting in an npc. cutin "3rd_mins_song04",2; //Tell the player about the instance requirements. mes "[ Instance Enter ]"; mes "You need between ^0000ff"+.p_rest+"^000000 and ^0000ff"+.p_rest[1]+"^000000 party members to join this instance."; mes "Also, your party members must be between the levels ^0000ff"+.p_lvlr+"^000000 and ^0000ff"+.p_lvlr[1]+"^000000."; if( .cost ) { set(.@b,-1); while(.@b++<.len) set .@message$, .@message$+ getitemname(.cost[.@b])+" x"+.amount[.@b]+((.len>1)?((.@b+1==.len)?"":((.@b+2==.len)?", and ":", ")):""); mes "And, you'll need: ^0000ff"+.@message$+"^000000."; } next; if ( !.@party_id ) { // Our guy doesn't have a party don't let him through. mes "[ Instance Enter ]"; mes "You need a party."; close2; cutin "",255; end; } //Asks the player if he'd like to destroy the instance. if ( instance_mapname( .md_mapn$ ) != "" ) { mes "Do you want to destroy this instance????"; next; if(select("Yes:No")==1) instance_destroy; } mes "[ Instance Enter ]"; mes "You're ready?"; next; if( select("Create Path:Cancel")==1 ) { if( getcharid(0) == getpartyleader(.@party_id,2) ) { // Check if our man is the party leader... getpartymember .@party_id; // Get number of party members. $@partymembercid[] set .@plen, $@partymembercount; // Move global variable to a local one. /* //Example how to count only online party members. getpartymember .@party_id,1; // Get number of party members. $@partymembercid[] getpartymember .@party_id,2; // Get number of party members. $@partymemberaid[] copyarray .@pcid[0],$@partymembercid[0],128; // Move the global array to a local one. copyarray .@paid[0],$@partymemberaid[0],128; // Move the global array to a local one. set .@plen, $@partymembercount; // Move global variable to a local one. while(.@i<.@plen) { // Remove offline members from the count. if(!isloggedin(.@paid[.@i],.@pcid[.@i])) { deletearray .@paid[.@i],1; deletearray .@pcid[.@i],1; } .@i++; } set .@plen, getarraysize(.@paid); // Get a new count with offline members removed. */ //Checking all the instance requirements. if( instance_mapname( .md_mapn$ ) != "" ) { mes "[ Instance Enter ]"; mes "I cannot reconnect the path... I'm sorry!"; close2; cutin "",255; end; } if( .@plen < .p_rest[0] || .@plen > .p_rest[1] ) { mes "[ Instance Enter ]"; mes "I'm sorry but you need at least "+.p_rest[0]+" party member."; mes "There is also a maximum of "+.p_rest[1]+" party members."; mes "adjust your party before you may enter."; close2; cutin "",255; end; } if( !instance_check_party( .@party_id, .p_rest, .p_lvlr[0], .p_lvlr[1] ) ) { mes "[ Instance Enter ]"; mes "I'm sorry but your party doesn't seem to meet the instance level requirements."; mes "Please adjust your party before you may enter."; close2; cutin "",255; end; } mes "[ Instance Enter ]"; mes "This place is dangerous. Please go back."; mes "If you don't have any business here, please go back."; next; while( .cost[.@a] ) // Checking for correct items. if( countitem( .cost[.@a] ) < .amount[.@a] ) break; else .@a++; if( .@a != .len ) { set( .@b, -1 ); while( .@b++ < .len ) set .@message$, .@message$+ getitemname(.cost[.@b])+" x"+.amount[.@b]+((.len>1)?((.@b+1==.len)?"":((.@b+2==.len)?", and ":", ")):""); mes "[ Instance Enter ]"; mes "I'm sorry but you need: ^0000ff"+.@message$+"^000000."; mes "Before you may enter this dungeon!"; close2; cutin "",255; end; } if( .@playtime == -1 ) {}// Quest doesn't exist fall through... else if( .@playtime == 0 || .@playtime == 1 ) { // Player is still waiting for the Cool-down quest... mes "[ Instance Enter ]"; mes "I'm sorry but you cannot enter right away."; mes "Poringz0rd still hasn't come out of hiding!"; close2; cutin "",255; end; } else erasequest .cooldown; // Remove completed cool down and fall through... .@instance = instance_create( .md_name$ ); if ( .@instance < 0 ) { // Try to create instance and set our instance ID. mes "[ Instance Enter ]"; mes "Party name is... "+getpartyname(.@party_id)+"."; mes "Party leader is... "+strcharinfo(0); mes "^0000ff"+.md_name$+"^000000 cannot be opened now."; // Instance creation failed... mes "Please try again later."; close2; cutin "",255; end; } // Instance creation successful letting everyone through. 'party_id = .@party_id; mes "[ Instance Enter ]"; mes "I will open the portal to"; mes "^0000ff"+.md_name$+"^000000 good luck!"; while(.cost[.@g]) { delitem(.cost[.@g],.amount[.@g]); .@g++; } close2; cutin "",255; sleep2(100); announce getpartyname(.@party_id)+" party has begun "+.md_name$+"!",bc_all,"0x00ff99"; addrid( 2, 0, .@party_id ); setquest .cooldown; instance_enter( .md_name$ ); end; } else { // Has a party but isn't the leader. mes "[ Instance Enter ]"; mes "Can I talk to the party leader?"; close2; cutin "",255; end; } } else { mes "[ Instance Enter ]"; mes "You're not worthy!"; close2; cutin "",255; end; } end; // Configuration OnInit: set .cooldown, 80008; // Set Cool-down quest ID. set .md_name$, "New Instance"; // Set Instance name. set .win, 10000; // If the party gets this or more zeny 100% to bonus. setarray .p_rest, 1, 8; // Set party restriction range. setarray .p_lvlr, 20, 99; // Party Level range. setarray .md_mapn$, "1@abys"; // First map in the instance. //setarray .cost, 501, 502; // Set Item ID. //setarray .amount, 1, 3; // Set Amount ID. set .len, getarraysize(.cost); // Length of our array. //Prize is the only thing I couldn't add to the configuration area. //It wouldn't've been optimal instead search for //callfunc("package_func",501,1,100,502,1,100,.mem_aid[.@i-1]); //and follow the function instructions to add more items. //if you need help just ask. }