Jump to content

Search the Community

Showing results for 'dress room'.

  • Search By Author

Content Type


Forums

  • Announcements
    • Rules & Guidelines
    • Community News
    • Development News
    • Ragnarok News
    • Community Crowdfunding
  • Support & Releases
    • General
    • Scripting
    • Database
    • Source
    • Graphic Enhancements
    • Web
    • Client-side
    • Third Party
    • Projects
  • Discussion & Suggestions
    • Database Discussion
    • Script Discussion
    • Source Discussion
    • Renewal Discussion
    • Archives
  • Community
    • rAthena General
    • Arts & Writings
    • Off Topic
  • International Forums
    • Filipino Support
    • German Support
    • Indonesian/Malaysian Support
    • Portuguese Support
    • Russian Support (Русский)
    • Spanish Support

Categories

  • Server Resources
    • Server Managers/Editors
    • Scripts
    • Source Modifications
  • Web Resources
    • General Website Templates
    • Forum Templates
    • FluxCP Themes
    • FluxCP Addons
    • Other Web/CP Scripts
  • Graphics Resources
    • Sprites & Palettes
    • Maps & 3D Resources
    • Other Graphics
  • Client Resources
    • GRF Files
    • Client Tools
    • Spriting & Paletting Tools
    • Texture & Mapping Tools
    • Editors
    • Patchers

Categories

  • Low Rate
  • Mid Rate
  • High Rate
  • Super High Rate

Categories

  • Records Test
  • Complete Installation Guides
  • Client Guides
    • Data Folder
  • MySQL Guides
  • Database Guides
  • Map Guides

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Location


Server


Github


Discord


Interests


Website URL


Yahoo


Skype

  1. Good morning guys! Could anyone help me with this script? I know this is a very old script... I would really like to implement this event on my server. The problem I'm having with it is that it doesn't start the game, everything goes fine but when the game starts it simply doesn't start. There is no way to guess in this case of poring. It is also showing these errors on my emulator. Script //==== eAthena Script ======================================= //= Poring Soccer Script //===== By: ================================================== //= [email protected] //= For ArcadyaOnline with Agora-online //= Translated to English by diedlikeahero & GM Team //===== Current Version: ===================================== //= 3.0 //===== Modified by: =========================================== //= Sonic //===== Compatible With: ===================================== //= Any eAthena Version //===== Description: ========================================= //= Football game made for Ragnarok Online, with a poring as a ball. //= The red team is on the east of the field //= The blue team is on the west of the field //===== New Modifications made by Sonic: ============================================= //= Added Reward Giver Npc //= Added Switch Ball function //= Fixed some bugs and errors //= Combined the script from 2 into 1 //= Added auto start warp portal appear in the prontera //= Added GM control to start or end the event //= Changed for newest pallete from pallete 78,79 to 74,75 //= Added waitingnpc room for joining (balancing players) //= Increased match time as member requested //= Fixed only party leaders can subscribe and unsubscribe match //= Added Judge Auto Commentator //= Added Weather Changer Function //= Added Own Goal message //= Set Wall surrounds ball2 map //= Added Red,blue fans,Bench Players,audience,cheer leaders & refree //= Allow spectators to enter the match to watch a real live soccer //= Added time out request function(only for party leaders) //= Added pay entrance fee system to spectate the match //= Added Game Ticket Exchanger to exchange ticket to Red or Blue Flag //= Added config to make it easier for setup to your own likings //= Fix of Npc sprite errors //= The fix with wrong reminder, Blue team kick to the right not left, and red team kick to the left not right //= Added cheat prevention: when the ball is out of field, if the opposite team does not kick the ball in within 5 seconds, both of the team have rights to kick in the ball //= Added special effect when scored goal //= Fixed waitingroom bug //===== Variables ============================================ //= Variables temporary servers (?) : //= $@state_match = 0 -> is free, writting possible //= $@state_match = 1 -> confirmation of writtings //= $@state_match = 2 -> a match is currently launching //= $@state_match = 3 -> a match is in play //= $@state_match = 4 -> delay after match //= //= $@score_blue_match //= $@score_red_match //= //= $@isballonfield = 0 -> yes, 1 -> no //= $@Activeplayers$ = name of the last player who hit the ball //= $@ActiveteamID = id of the last team that hit the ball //= //= $@teampossessingballID = id of the red team or the blue team //= //= $@blueteamID = id of blue team //= $@redteamID = id of red team //= //=$@redconfirmation -> 0 : not confirmed, 1 : confirmed, 2 : request to cancel //=$@blueconfirmation //= //===== Prerequisite ========================================== //= A football field : ball2 //= 2 palettes (one for the red team and one for the blue team) here the palettes 74 and 75. //= (see OnInit method of the organizer) //= red palette : $paletteRed //= blue palette : $paletteBlue //============================================================= - script PBE#disable -1,{ OnInit: //===================CONFIGURATION=====================================\\ //You may configure it to your own likings set $@PrizeItemID[1],7179; //Poring Soccer Event Prize set $@Amount[1],1; //Amount of the prize set $@entrancefee,50000; //Entrance fee if want to spectate the match set $@gameticket[1],0; //On or off the red & blue game ticket exchanger---> 1 for off, 0 for on set $@ticket,6157; //ID of the ticket set $@hatID[1],21000; //Red Flag Hat ID set $@hatID[2],21001; //Blue Flag Hat ID //=====================================================================\\ disablenpc "poringballwarp"; disablenpc "Reward Giver"; delwall "PWall1"; delwall "PWall2"; delwall "PWall3"; delwall "PWall4"; delwall "PWall5"; delwall "PWall6"; delwall "PWall7"; delwall "PWall8"; delwall "PWall9"; delwall "PWall10"; delwall "PWall11"; delwall "PWall12"; delwall "PWall13"; delwall "PWall14"; delwall "PWall15"; delwall "PWall16"; delwall "PWall17"; delwall "PWall18"; delwall "PWall19"; delwall "PWall20"; setwall "ball2",117,91,100,2,0,"PWall1"; setwall "ball2",110,21,109,2,0,"PWall2"; setwall"ball2",10,21,32,0,0,"PWall3"; setwall "ball2",10,61,31,0,0,"PWall4"; setwall "ball2",110,22,30,0,0,"PWall5"; setwall "ball2",110,61,30,0,0,"PWall6"; setwall "ball2",11,51,3,2,0,"PWall7"; setwall "ball2",7,52,10,0,0,"PWall8"; setwall "ball2",11,61,3,4,0,"PWall9"; setwall "ball2",10,22,29,0,0,"PWall10"; setwall "ball2",8,51,1,0,0,"PWall11"; setwall "ball2",8,61,2,6,0,"PWall12"; setwall "ball2",109,61,1,0,0,"PWall13"; setwall "ball2",109,51,1,0,0,"PWall14"; setwall "ball2",112,51,2,2,0,"PWall15"; setwall "ball2",112,61,2,2,0,"PWall16"; setwall "ball2",113,61,10,4,0,"PWall17"; setwall "ball2",111,91,6,2,0,"PWall18"; setwall "ball2",11,91,6,6,0,"PWall19"; setwall "ball2",17,91,1,0,0,"PWall20"; if ( $@gameticket[1] ) { disablenpc "Game Ticket Dealer#cred1"; disablenpc "Game Ticket Dealer#cblue1"; end; } } prontera,163,177,3 script Poring Soccer Hoster 917,{ mes "^BF0073[ Poring Hoster]^000000"; cutin "",255; cutin "god_kukur02",2; mes "Hi "+strcharinfo(0)+"! What do you wish me to do for you?"; switch(select("I want to start this event!","I want to spectate the match!","Nothing, just hanging around.")) { case 1: if ($@state_match>=2) { mes "There is a match going on already"; close; } if (getgmlevel() >= 60) { mes "Starting the event now..."; cutin "",255; close2; goto sonicxxx; end; } mes "Only GM are allowed to start the event!!"; close; case 2: if ($@state_match>=2) { mes "You need to pay in order to watch the match!"; mes "Entrance fee is ^ff0000"+$@entrancefee+" zeny^000000, would you like to pay and proceed?"; next; mes "You will receive a game ticket after u have paid."; mes "And you can exchange your game ticket with the ^FF7F50Game Ticket Exchanger NPC^000000"; switch(select("What!? thats too expensive to watch a stupid match!:Sure, why not? xD")) { case 1: mes "Alright then, go do your stupid things and make sure you dont come back!"; cutin "",255; close; end; case 2: if ( zeny < $@entrancefee ) { mes "You dont have sufficent zeny!"; next; mes "Get out of here! Go find some zeny.."; cutin "",255; close; } set Zeny, Zeny - $@entrancefee; mes "Good!,so which team do you support?"; switch(select("^FF3333Red^000000 team!:^37FDFCBlue^000000 team!")) { case 1: mes "Okay, I will now send to the spectate the match!"; getitem $@ticket,1; warp "ball2",5,56; close; case 2: mes "Okay, I will now send to the spectate the match!"; getitem $@ticket,1; warp "ball2",114,56; close; } } } mes "There is no match in progress."; mes "There are currently "+getmapusers("force_3-3")+" Players in the Waiting Room."; cutin "",255; close; case 3: mes "Okay,Feel free to come again if you change your mind."; cutin "",255; close; end; } sonicxxx: announce "[ Poring Hoster ]: Poring Soccer Event has just started!!!",bc_all; sleep 3000; announce "[ Poring Hoster ]: For those who wants to register, please make two party of 5 players each.",bc_all; sleep 2500; announce "[ Poring Hoster ]: After ready then go to the left portal in the center of prontera!",bc_all; enablenpc "poringballwarp"; initnpctimer; end; OnTimer80000: announce "Poring Soccer Hoster: Last 10 seconds.",0; end; OnTimer81000: announce "Poring Soccer Hoster: 5.",0; end; OnTimer82000: announce "Poring Soccer Hoster: 4.",0; end; OnTimer83000: announce "Poring Soccer Hoster: 3.",0; end; OnTimer84000: announce "Poring Soccer Hoster: 2.",0; end; OnTimer85000: announce "Poring Soccer Hoster: 1.",0; end; OnTimer86000: announce "Poring Soccer Hoster: Time's up.",0; end; OnTimer90000: disablenpc "poringballwarp"; end; OnTimer105000: stopnpctimer; mapwarp "force_3-3","prontera",164,178; set $@state_match,0; end; } force_3-3,14,22,3 script RED TEAM PARTY 793,{ OnInit: startnpctimer; waitingroom "Red Team",6,"OnWarpToArea",5; enablewaitingroomevent; end; OnTimer1000: npctalk "You have 15 seconds to enter the chatroom."; end; OnTimer10000: npctalk "You have 5 seconds to enter the chatroom."; end; OnTimer15000: npctalk "Times up!"; stopnpctimer; end; OnWarpToArea: warp "quiz_02",334,362; disablewaitingroomevent; end; } force_3-3,25,22,3 script BLUE TEAM PARTY 109,{ OnInit: startnpctimer; waitingroom "Blue Team",6,"OnWarpToArea1",5; enablewaitingroomevent; end; OnTimer1000: npctalk "You have 15 seconds to enter the chatroom."; end; OnTimer10000: npctalk "You have 5 seconds to enter the chatroom."; end; OnTimer15000: npctalk "Times up!"; stopnpctimer; end; OnWarpToArea1: warp "quiz_02",334,362; disablewaitingroomevent; end; } prontera,162,182,0 warp poringballwarp 2,2,force_3-3,20,12 quiz_02,349,379,4 script Organizer#orga_ball 869,{ cutin "lhz_diguts02",2; set @palette, getlook(7); if ($@state_match == 1) goto OnConfirmation; if ($@state_match >= 2) goto OnMatchinplay; Showgamerules: mes "[Organizer]"; mes "Poring Soccer is quite a simple game,"; mes "you have to send the poring in the adversary's goal."; mes "The team that makes the most goals will win the match."; next; mes "[Organizer]"; mes "But before going on the field, 2 teams must be made."; mes "All the members of one team have to be in the same group."; mes "Then a person of each group will go subscribe to one of the assistants."; mes "When 2 teams are subscribed, you will have to give me your confirmation."; mes "Once the teams are confirmed, all the players must come see me to be sent to the trainers."; mes "The trainers will send you on the field, the match will not wait for you so hurry!"; next; mes "[Organizer]"; mes "If the subscriptions slack off too much they will be cancelled to open their place to more active teams..."; goto OnClose; // OnSubscriptionteam called by the assistants during the subscription of each team OnSubscriptionteam: // if the 2 teams are subscribed if (($@redteamID!=0) && ($@blueteamID!=0) && (getpartyname($@redteamID)!="null") && (getpartyname($@blueteamID)!="null")) { npctalk "The 2 teams are ready : "+getpartyname($@blueteamID)+" and "+getpartyname($@redteamID)+"."; npctalk "You have 1 minute so that a member of each team can come confirm the subscription by talking to me."; if ($@state_match!=1) { set $@state_match, 1; stopnpctimer; initnpctimer; } } end; OnConfirmation: if ((getcharid(1)!=$@redteamID) && (getcharid(1)!=$@blueteamID)) { // if the player isn't in one of the teams send him back to the game rules. goto Showgamerules; } if (getcharid(1)==$@redteamID) { // confirm if the player is part of the red team mes "[Organizer]"; mes "Thank you for confirming with the Red Team."; if ($@redconfirmation==1) goto OnClose; // if we have already confirmed, no need to go further. set $@redconfirmation, 1; close2; } // else if (getcharid(1)==$@blueteamID) { // confirm if player is part of the blue team mes "[Organizer]"; mes "Thank you for confirming with the Blue Team."; if ($@blueconfirmation==1) goto OnClose; // if we have already confirmed, no need to go further. set $@blueconfirmation, 1; close2; } // verify that the groups haven't been sorted if ((getpartyname($@redteamID)=="null") || (getpartyname($@blueteamID)=="null")) { announce "Organizer : The teams are not valid anymore, the match is cancelled...",bc_yellow|bc_map; stopnpctimer; callsub OnMatchcancellation; goto OnClose; end; } if (($@state_match!=2) && ($@blueconfirmation==1) && ($@redconfirmation==1)) { stopnpctimer; announce "Organizer : The match will begin soon! ALL the players must contact me to be transferred on to the field.",bc_yellow|bc_map; set $@state_match, 2; donpcevent "TimerInitMatch::OnStart"; } cutin "",255; end; OnTimer60000: announce "Organizer : The delay of the confirmation has passed, the match is cancelled...",bc_npc|bc_map; callsub OnMatchcancellation; end; OnMatchcancellation: set $@state_match, 0; set $@blueteamID, 0; set $@redteamID, 0; set $@redconfirmation, 0; set $@blueconfirmation, 0; set $@isballonfield, 0; set $@teampossessingballID, 0; return; OnMatchinplay: if (getcharid(1)==$@redteamID) { // if the player is from the red team mes "[Organizer]"; mes "Ready to play?"; switch (select("I want to go on the field.","I want to cancel the match.")) { case 1: // Test actual palette if (@palette != $paletteRed) { if (@palette != $paletteBlue) { // The player isn't wearing a suit, you need to save his suit at the lockers, to give it back after set savePalette, @palette; } setlook 7, $paletteRed; } savepoint "quiz_02",364,345; percentheal 100,100; warp "quiz_02",364,345; goto OnClose; case 2: cutin "",255; cutin "lhz_diguts07",2; set $@redconfirmation,2; announce "Organizer : "+strcharinfo(0)+" of the Red Team asks for a match cancellation.",bc_npc|bc_map; } } else if (getcharid(1)==$@blueteamID) { // if the player is from the blue team mes "[Organizer]"; mes "Ready to play?"; switch (select("I want to go on the field.","I want to cancel the match.")) { case 1: // Test actual palette if (@palette != $paletteBlue) { if (@palette != $paletteRed) { // The player isn't wearing a suit, you need to save his suit at the lockers, to give it back after set savePalette, @palette; } setlook 7, $paletteBlue; } savepoint "quiz_02",335,345; percentheal 100,100; warp "quiz_02",335,345; goto OnClose; case 2: cutin "",255; cutin "lhz_diguts07",2; set $@blueconfirmation,2; announce "Organizer : "+strcharinfo(0)+" of the Blue Team asks for a match cancellation.",bc_npc|bc_map; } } else { // if the player isn't in one of the teams send him back to the game rules. goto Showgamerules; } if (($@blueconfirmation==2) && ($@redconfirmation==2)) { announce "Organizer : Like the 2 teams wish, the match is cancelled!",bc_npc|bc_map; callsub OnMatchcancellation; donpcevent "TimerMatchcancellation::OnMatchcancellation"; end; } goto OnClose; // At the start of map server : OnInit: set $paletteRed, 74; set $paletteBlue, 75; // Warp all the players from map ball2 near the Organizer. callsub OnMatchcancellation; end; OnClose: close2; cutin "",255; end; } quiz_02,363,365,4 script Red Clan#ass_coach_R 911,{ // If a match is in play if ($@state_match >= 2) { mes "[Red Assistant]"; mes "The subscriptions are currently unavailable because a match is in progress. Don't hesitate to try again in a few minutes!"; close; } // Does the player belong to a group? if (getcharid(1)==0) { mes "[Red Assistant]"; mes "The subscriptions are for party, and you're not in a party."; next; mes "Come back with your friends!"; close; } // Isn't the group of the player subscribed as the blue team? if (getcharid(1)==$@blueteamID) { mes "[Red Assistant]"; mes "Hey! A player from the opposing team! Get ready to face off one of the best teams!"; mes "The formidable Red Team!"; close; } // Only party leader can talk with him if(getpartyleader(getcharid(1),2) != getcharid(0)){ mes "[Red Assistant]"; mes "I will speak only with your party leader!"; close; } // If a team is already subscribed, and that team still exists if (($@redteamID!=0) && (getpartyname($@redteamID)!="null")) { // if the player belongs to that team that's already subscribed // Only party leader can talk with him if ($@redteamID==getcharid(1)) { mes "[Red Assistant]"; mes "Do you wish to unsubscribe your team?"; next; if (select("Yes, we want to stop the match.","No, we're staying.")==2) close; // if the player wishes to unsubscribe their team announce "Team "+getpartyname($@redteamID)+" has disbanded. There is no more Red Team!",bc_yellow|bc_map; set $@redteamID, 0; close; } mes "[Red Assistant]"; mes "A team is already subscribed! It's Team "+getpartyname($@redteamID)+"."; close; } // if there are no teams subscribed and that the subscriptions are open // Only party leader can talk with him mes "[Red Assistant]"; mes "Do you wish to subscribe your team?"; next; if (select("Yes, we want to subscribe.","No.")==2) close; // Team subscription if ($@redteamID==0 || (getpartyname($@redteamID)=="null")) { // Only party leader can talk with him set $@redteamID, getcharid(1); mes "[Red Assistant]"; mes "Your team is now subscribed, good luck!"; announce ""+getpartyname($@redteamID)+" Team has subscribed as the Red Team!",bc_yellow|bc_map; close2; npctalk "Please talk to Organizer after you have subscribe for your party!"; doevent "Organizer#orga_ball::OnSubscriptionteam"; } else { mes "[Red Assistant]"; mes "I'm sorry! Another team has subscribed before you..."; close2; } end; } quiz_02,336,365,4 script Blue Clan#ass_coach_B 912,{ // If a match is in play if ($@state_match >= 2) { mes "[Blue Assistant]"; mes "The subscriptions are currently unavailable because a match is in progress. Don't hesitate to try again in a few minutes!"; close; } // Does the player belong to a group? if (getcharid(1)==0) { mes "[Blue Assistant]"; mes "The subscriptions are for party, and you're not in a party."; next; mes "Come back with your friends!"; close; } // Isn't the group of the player subscribed as the red team? if (getcharid(1)==$@redteamID) { mes "[Blue Assistant]"; mes "Hey! A player from the opposing team! Get ready to face off one of the best teams!"; mes "The formidable Blue Team!"; close; } // Only party leader can talk with him if(getpartyleader(getcharid(1),2) != getcharid(0)){ mes "[Blue Assistant]"; mes "I will speak only with your party leader!"; close; } // If a team is already subscribed, and that team still exists if (($@blueteamID!=0) && (getpartyname($@blueteamID)!="null")) { // if the player belongs to that team that's already subscribed if ($@blueteamID==getcharid(1)) { mes "[Blue Assistant]"; mes "Do you wish to unsubscribe your team?"; next; if (select("Yes, we want to stop the match.","No, we're staying.")==2) close; // if the player wishes to unsubscribe their team announce "Team "+getpartyname($@blueteamID)+" has disbanded. There is no more Blue Team!",bc_yellow|bc_map; set $@blueteamID, 0; close; } mes "[Blue Assistant]"; mes "A team is already subscribed! It's Team "+getpartyname($@blueteamID)+"."; close; } // if there are no teams subscribed and that the subscriptions are open mes "[Blue Assistant]"; mes "Do you wish to subscribe your team?"; next; if (select("Yes, we want to subscribe.","No.")==2) close; // Team subscription // Only party leader can talk with him if ($@blueteamID==0 || (getpartyname($@blueteamID)=="null")) { set $@blueteamID, getcharid(1); mes "[Blue Assistant]"; mes "Your team is now subscribed, good luck!"; announce ""+getpartyname($@blueteamID)+" Team has subscribed as the Blue Team!",bc_yellow|bc_map; close2; npctalk "Please talk to Organizer after you have subscribe for your party!"; doevent "Organizer#orga_ball::OnSubscriptionteam"; } else { mes "[Blue Assistant]"; mes "I'm sorry! Another team has subscribed before you..."; close2; } end; } quiz_02,373,336,4 script Red Coach#coach_R 911,{ mes "[Red Coach]"; if (getcharid(1)==$@blueteamID) { mes "HEY BLUE TEAM!!! WHAT THE HELL YOU DOING HERE!?"; close2; goto OnLeave; } if ($@state_match<=1) { mes "It looks like you got nothing to do here..."; close2; goto OnLeave; } mes "Hello, I am the Coach of the Red Team!"; next; percentheal 100,100; switch(select("Go on the field","Leave","Cancel")) { case 1: // If the match begins, warp immediately, if ($@state_match==2) goto OnReadyformatch; // otherwise, determine waiting time before being rewarped on the field set @waiting_time, 3000; if ($@state_match==3) { mes "[Red Coach]"; mes "You will be sent on the field in "+(@waiting_time/1000)+ " seconds, be ready!"; close2; addtimer @waiting_time, "Red Coach#coach_R::OnReadyformatch"; } break; case 2: goto OnLeave; break; case 3: break; } close; OnLeave: warp "quiz_02",350,374; close; // Warp on the field OnReadyformatch: set @poringBallAura, 0; warp "ball2",66,56; end; } quiz_02,326,336,4 script Blue Coach#coach_B 912,{ mes "[Blue Coach]"; if (getcharid(1)==$@redteamID) { mes "HEY RED TEAM!!! WHAT THE HELL YOU DOING HERE!?"; close2; goto OnLeave; } if ($@state_match<=1) { mes "It looks like you got nothing to do here..."; close2; goto OnLeave; } mes "Hello, I am the coach of the Blue Team!"; next; percentheal 100,100; switch(select("Go on the field","Leave","Cancel")) { case 1: // If the match begins, warp immediately, if ($@state_match==2) goto OnReadyformatch; // otherwise, determine waiting time before being rewarped on the field else if ($@state_match==3) { set @waiting_time, 3000; mes "[Blue Coach]"; mes "You will be sent on the field in "+(@waiting_time/1000)+ " seconds, be ready!"; close2; addtimer @waiting_time, "Blue Coach#coach_B::OnReadyformatch"; } break; case 2: goto OnLeave; break; case 3: break; } close; OnLeave: warp "quiz_02",350,374; close; end; // Warp on the field OnReadyformatch: set @poringBallAura, 0; warp "ball2",54,56; close; } - script TimerInitMatch -1,{ OnStart: // countdown before the match begins pvpoff "ball2"; set $@teampossessingballID, 0; set $@bothteam,1; set $@score_blue_match, 0; set $@score_red_match, 0; stopnpctimer; // normally pointless, but seeing the consequences of a npc timer, we won't take a chance. initnpctimer; //doevent "Ball::OnReturntomiddle"; end; OnTimer15000: mapannounce "ball2", "Match will begin in 30 seconds.",bc_map; end; OnTimer20000: mapannounce "ball2", "Match will begin in 25 seconds.",bc_map; sleep 5000; mapannounce "ball2", "In the mean time, you can go down and talk to field assistant to switch the ball or change weather if you want^^.",bc_map; end; OnTimer30000: mapannounce "ball2", "Match will begin in 20 seconds.",bc_map; end; OnTimer40000: mapannounce "ball2", "Match will begin in 15 seconds.",bc_map; end; OnTimer50000: mapannounce "ball2", "Match will begin in 10 seconds.",bc_map; end; OnTimer60000: mapannounce "ball2", "Match will begin in 5 seconds.",bc_map; sleep 5000; mapannounce "ball2", "A friendly reminder: BLUE team shoot to the right goal, RED TEAM shoot to the left goal! REMEMBER THAT! and try not to OWN GOAL!",bc_map; end; OnTimer75000: mapannounce "ball2", "The match has begun! Go do your best!",bc_map; stopnpctimer; donpcevent "TimerMatch::OnStartMatch"; end; } - script TimerMatch -1,{ OnStartMatch: stopnpctimer; // normally pointless, but seeing the consequences of a npc timer, we won't take a chance. initnpctimer; set $@timedelay,0; set $@state_match,3; end; OnTimer20000: mapannounce "ball2", "Judge: Get the fires up! Lets get this match an interesting match!!",bc_map; end; OnTimer80000: mapannounce "ball2", "Judge: Wow, two teams are now struggling hard for a goal..",bc_map; end; OnTimer140000: mapannounce "ball2", "Judge: Hey, hey, hey....DO YOUR BEST EVERYONE!!!",bc_map; end; OnTimer200000: mapannounce "ball2", "Judge: 30 seconds remaining to half time...",bc_map; end; OnTimer220000: mapannounce "ball2", "Halftime! Score is currently "+$@score_blue_match+" (Blue) / "+$@score_red_match+" (Red)",bc_map; set $@state_match,9; sleep2 5000; mapannounce "ball2", "Judge: Everyone rest for 1 minutes before continueing..",bc_map; sleep2 6000; mapannounce "ball2", "Judge: You can walk down to talk to Field Assistant to switch the ball & change weather based on what you like if you want^^",bc_map; pvpoff "ball2"; end; OnTimer280000: mapannounce "ball2", "Its time for second quarter match! Everyone please get ready!!!",bc_map; sleep2 5000; mapannounce "ball2", "Second quarter match has begun! Go! go! go!",bc_map; set $@state_match,3; end; OnTimer340000: mapannounce "ball2", "Judge: Good job! Keep it up everyone~",bc_map; end; OnTimer400000: if ($@score_blue_match<$@score_red_match) { mapannounce "ball2", "Judge: LOL! Blue Team! what are you all doing? Don't give up! You can do it!!",bc_map; } else if ($@score_red_match<$@score_blue_match) { mapannounce "ball2", "Judge: LOL! Red Team! what are you all doing? Don't give up! You can do it!!",bc_map; } else mapannounce "ball2", "Judge: LOL! Both Team! what are you all doing? A tie score!? audience is complaining now! Dont make your supporter dissapointed :<",bc_map; end; OnTimer460000: if ($@score_blue_match<$@score_red_match) { mapannounce "ball2", "Judge: Red Team! You done well, now defend is the key to success!",bc_map; } else if ($@score_red_match<$@score_blue_match) { mapannounce "ball2", "Judge: Blue Team! You done well, now defend is the key to success now!",bc_map; } else mapannounce "ball2", "Judge: Two teams are now same score..will them hang until full time? or is there miracle happening soon? We shall see^^",bc_map; end; OnTimer520000: mapannounce "ball2", "30 seconds remaining to full time...",bc_map; end; OnTimer540000: mapannounce "ball2", "The match is over! Scores end with "+$@score_blue_match+" (Blue) - "+$@score_red_match+" (Red)",bc_map; set $@state_match,4; pvpoff "ball2"; end; OnTimer545000: if ($@score_blue_match<$@score_red_match) { mapannounce "ball2", "Congratulations to the Red Team!!",bc_map; mapannounce "ball2", "Go and claim your reward from Reward Giver Npc!",bc_map; enablenpc "Reward Giver"; } else if ($@score_blue_match>$@score_red_match) { mapannounce "ball2", "Congratulations to the Blue Team!!",bc_map; mapannounce "ball2", "Go and claim your reward from Reward Giver Npc!",bc_map; enablenpc "Reward Giver"; } else mapannounce "ball2", "It's a tie!! Try harder next time~",bc_map; donpcevent "Ball::OnReturntomiddle"; end; OnTimer580000: mapannounce "ball2", "You got 30 seconds left to claim your prize and you will be warped back!!",bc_map; end; OnTimer620000: stopnpctimer; disablenpc "Reward Giver"; mapwarp "ball2","quiz_02",350,374; set $@state_match,0; set $@blueteamID, 0; set $@redteamID, 0; set $@redconfirmation, 0; set $@blueconfirmation, 0; set $@teampossessingballID, 0; end; } ball2,60,64,3 script Reward Giver 932,{ mes "Come and claim your rewards if only you have won."; next; if ($@score_blue_match<$@score_red_match) { npctalk "Talk to me red team!!!"; if (getcharid(1)==$@blueteamID) goto L_false; if ( $prize_claimed[1] ) goto L_claimed; mes "There you go!"; getitem $@PrizeItemID[1],$@Amount[1]; set $prize_claimed[1], 1; close; } if ($@score_blue_match>$@score_red_match) { npctalk "Talk to me blue team!!!"; if (getcharid(1)==$@redteamID) goto L_false; if ( $prize_claimed[2] ) goto L_claimed; mes "There you go!"; getitem $@PrizeItemID[1],$@Amount[1]; set $prize_claimed[2], 1; close; } L_false: mes " Your team doesn't win!"; next; mes " Try harder next time ^_^"; close; L_claimed: mes " You already have the reward!!!"; next; mes " Don't ever try to scam me!"; close; end; } - script TimerMatchcancellation -1,{ OnMatchcancellation: set $@state_match, 4; mapannounce "ball2", "Score is currently "+$@score_blue_match+" (Blue) / "+$@score_red_match+" (Red)",bc_map; mapannounce "ball2", "The match has been cancelled to a team or coach's request!",bc_map; donpcevent "Ball::OnReturntomiddle"; stopnpctimer; initnpctimer; end; OnTimer4000: stopnpctimer; mapwarp "ball2","quiz_02",350,374; set $@state_match,0; end; } ball2,60,56,4 script Ball 1002,{ // Kicking the ball allows it to move from many squares, // however its location is determined square by square. // The ball draws its course by moving forward from a square every 150 ms. // Every time it lands on a square it makes some tests to determine if a goal has been made, // if it came out of the field, etc. // If that is the case it returns to its place on its own (middle of the field, corners, etc.) if ($@timedelay==1) { npctalk "A team has requested for time out.. Please wait for 1 minute!"; end; } if ($@state_match!=3) { // If there are no matches in progress ( hasn't started yet, just finished, etc.) npctalk "No match! Don't touch!"; end; } if ($@destinationType>0) { end; } // If the player isn't in one of the 2 subscribed teams : if ((getcharid(1) == 0) || ((getcharid(1) != $@redteamID) && (getcharid(1) != $@blueteamID))) { npctalk "A trespasser!! Get out "+strcharinfo(0)+" !"; warp "quiz_02",350,374; end; } set $@Activeplayers$, strcharinfo(0); set $@ActiveteamID, getcharid(1); // Player and ball coordinates at the time of the shot getmapxy $@mapname$,$@mapxNPC,$@mapyNPC,1; getmapxy $@mapname$,$@mapxPC,$@mapyPC,0; // verification of the player's distance / ball : the player must be 1 square from the ball. if (distance($@mapxNPC,$@mapyNPC,$@mapxPC,$@mapyPC)>2) { dispbottom "You cannot shoot the Poring ball at distance."; end; } // Watch out for the position of the stopnpctimer, some tests must be made beforehand (has the player really hit the ball?) stopnpctimer; specialeffect 26; specialeffect 44; npcspeed 30; // random distance set .@rand, rand(0,10); set $@distance,.@rand; switch(rand(9)) { //Random effect of the ball case 0: if( rand(50) < 30 ) { atcommand "@nuke "+strcharinfo(0); break; } case 1: sc_start SC_CONFUSION,7000,0; break; case 2: sc_start SC_PARALYSE,10000,0; break; case 3: sc_start SC_WINDWALK,10000,0; break; case 4: sc_start SC_Curse,10000,0; break; case 5: sc_start SC_POISON,100000,0; break; case 6: sc_start SC__MANHOLE,7000,0; break; case 7: dispbottom "You been time travelled."; warp "ball2",60,57; break; case 8: sc_start SC_INCREASEAGI,10000,0; break; } // Research of the position of the ball X if ($@mapxPC<$@mapxNPC) set $@movementX, 1; else if ($@mapxPC>$@mapxNPC) set $@movementX, -1; else set $@movementX, 0; // Research of the position of the ball Y if ($@mapyPC<$@mapyNPC) set $@movementY, 1; else if ($@mapyPC>$@mapyNPC) set $@movementY, -1; else set $@movementY, 0; // If the ball is already out of the field, it cannot be moved further away from the field if ($@isballonfield==1) { mapannounce "ball2", "The other team will be given 5 seconds to kick the ball in, otherwise both team can kick the ball.",0xFF0000; donpcevent "TimesOut::OnTimes"; if ((23>=$@mapyNPC+$@movementY)||($@mapyNPC+$@movementY>=89)||(12>=$@mapxNPC+$@movementX)||($@mapxNPC+$@movementX>=108)) end; } // Check if the ball is in a team's possession (for example after the ball's been kicked out of the field by a team, // only the other team has the right to give the first hit to the ball) if ($@teampossessingballID != 0) && ($@ActiveteamID != $@teampossessingballID) && ($@bothteam != 0) { dispbottom "The other team gets the Poring."; end; } else set $@teampossessingballID, 0; // start of the ball's movement set $@mapxNPC, $@mapxNPC+$@movementX; set $@mapyNPC, $@mapyNPC+$@movementY; npcwalkto $@mapxNPC,$@mapyNPC; //npctalk "npcwalkto A "+$@mapxNPC+" "+$@mapyNPC; goto Whereistheball; end; OnBallSwitch: if ( $@switchball[1] ) { set $monster, 1031; setnpcdisplay "Ball",$monster; set $@switchball[1], 0; end; } if ( $@switchball[2] ) { set $monster, 1113; setnpcdisplay "Ball",$monster; set $@switchball[2], 0; end; } if ( $@switchball[3] ) { set $monster, 1613; setnpcdisplay "Ball",$monster; set $@switchball[3], 0; end; } if ( $@switchball[4] ) { set $monster, 1242; setnpcdisplay "Ball",$monster; set $@switchball[4], 0; end; } if ( $@switchball[5] ) { set $monster, 1582; setnpcdisplay "Ball",$monster; set $@switchball[5], 0; end; } if ( $@switchball[6] ) { set $monster, 1388; setnpcdisplay "Ball",$monster; set $@switchball[6], 0; end; } if ( $@switchball[7] ) { set $monster, 1120; setnpcdisplay "Ball",$monster; set $@switchball[7], 0; end; } if ( $@switchball[8] ) { set $monster, 1784; setnpcdisplay "Ball",$monster; set $@switchball[8], 0; end; } if ( $@switchball[9] ) { set $monster, 1904; setnpcdisplay "Ball",$monster; set $@switchball[9], 0; end; } if ( $@switchball[10] ) { set $monster, 1002; setnpcdisplay "Ball",$monster; set $@switchball[10], 0; end; } OnTimer150: stopnpctimer; getmapxy $@mapname$,$@mapxNPC,$@mapyNPC,1; //npctalk "getmapxy "+$@mapxNPC+" "+$@mapyNPC; // Research of the direction if the ball already has one if ($@destinationType>0) { switch($@destinationType) { case 0: break; case 1: // Go to the middle of the field set $@destinationX, 60; set $@destinationY, 56; break; case 2: // Go to the North West corner set $@destinationX, 15; set $@destinationY, 86; break; case 3: // Go to the North East corner set $@destinationX, 105; set $@destinationY, 86; break; case 4: // Go to the South West corner set $@destinationX, 15; set $@destinationY, 26; break; case 5: // Go to the South East corner set $@destinationX, 105; set $@destinationY, 26; break; case 6: // Go to the West Goal set $@destinationX, 19; set $@destinationY, 56; break; case 7: // Go to the East Goal set $@destinationX, 101; set $@destinationY, 56; break; } // Research of the movement X of the ball to get closer to destination if ($@destinationX<$@mapxNPC) set $@movementX, -1; else if ($@destinationX>$@mapxNPC) set $@movementX, 1; else set $@movementX, 0; // Research of the movement Y of the ball to get closer to destination if ($@destinationY<$@mapyNPC) set $@movementY, -1; else if ($@destinationY>$@mapyNPC) set $@movementY, 1; else set $@movementY, 0; // Movement of the ball npcwalkto $@mapxNPC+$@movementX,$@mapyNPC+$@movementY; getmapxy $@mapname$,$@mapxNPC,$@mapyNPC,1; // if the ball still hasn't reached its destination, restart the timer if (($@mapxNPC==$@destinationX) && ($@mapyNPC==$@destinationY)) set $@destinationType,0; else { stopnpctimer; initnpctimer; } end; } // save the coordinates " before movement " (to delete the players from the minimaps) //set $@mapxNPCold, $@mapxNPC; //set $@mapyNPCold, $@mapyNPC; // If the ball doesn't have a precise destination, it continues its previous movement set $@mapxNPC, $@mapxNPC+$@movementX; set $@mapyNPC, $@mapyNPC+$@movementY; npcwalkto $@mapxNPC,$@mapyNPC; //npctalk "npcwalkto B "+$@mapxNPC+" "+$@mapyNPC; // Update the movement of the Poring on the minimap // for every player on the map // affects rid with a thing like : getcharid(3) //attachrid($@thingmabob_rid); // delete old save point // draw new save point goto Whereistheball; end; OnReturntomiddle: set $@destinationType, 1; stopnpctimer; initnpctimer; end; Whereistheball: // Note : // the command "getmapxy $@mapname$,$@mapxNPC,$@mapyNPC,1;" previously used here // wasn't allowing enough time for the ball to move, and often gave its coordinated to the movement // so instead I update the coordinates of the ball manually when it is being moved. This means that we work with // the " supposed " coordinates of the ball. // If the supposed coordinates ever didn't fit with the real coordinates, there would be a need to think // a way to give the ball the time to move, before doing the getmapxy. //If the ball was out, test if it came back on the field if ($@isballonfield==1) { if (((23<$@mapyNPC)&&($@mapyNPC<89))&&((12<$@mapxNPC)&&($@mapxNPC<108))) { mapannounce "ball2", "The Poring is back on the field.",bc_blue; set $@isballonfield,0; } } else { if ($@mapxNPC>=108) { // T h e b a l l i s o n t h e e a s t s i d e // Check if we are in the right-side goal if ((53<=$@mapyNPC)&&($@mapyNPC<=59)) { mapannounce "ball2", " "+$@Activeplayers$+" from the "+getpartyname($@blueteamID)+" party has scored a goal for the Blue Team!",bc_yellow; if ($@ActiveteamID==$@blueteamID) { specialeffect 89; mapannounce "ball2", " Nice shot! "+$@Activeplayers$+" you made blue team proud xD!",bc_blue; atcommand "@npctalk Blue Fans#fblue9,I love you, Blue Team!"; atcommand "@npctalk Blue Fans#fblue8,Keep up the good work!"; atcommand "@npctalk Blue Fans#fblue7,Nice job!"; atcommand "@npctalk Blue Fans#fblue6,I know you can do it, you didnt dissapoint me~"; atcommand "@npctalk Blue Fans#fblue5,Yee haw!"; atcommand "@npctalk Blue Fans#fblue4,Red Team..YOU SUCK!"; atcommand "@npctalk Blue Fans#fblue3,Blue Team is the best!"; } else { mapannounce "ball2", "SWT!!! "+$@Activeplayers$+" has just shot an own goal!!! ERWWWW..."+$@Activeplayers$+"! ",bc_blue; mapannounce "ball2", " Red teams supporters are angry at "+$@Activeplayers$+" that made red team ashamed =< and the blue teams supporters are laughing out loud! HAHAHAAHA!!!!!",bc_blue; } npctalk "Goal! I'll return to the middle of the field."; set $@score_blue_match, $@score_blue_match+1; set $@destinationType, 1; set $@teampossessingballID, $@redteamID; stopnpctimer; initnpctimer; end; } // if we are not in the goal, mapannounce "ball2", " "+$@Activeplayers$+" has sent the Poring Ball out of the field!",0xFF0000; mapannounce "ball2", "The other team will be given 5 seconds to kick the ball in, otherwise both team can kick the ball.",0xFF0000; set $@isballonfield,1; if ($@ActiveteamID==$@redteamID) { // If the ball gets kicked by a player from the defending team, send the ball in the right corner : if ($@mapyNPC<=56) { npctalk "Out of the field! I am going to the corner."; set $@destinationType, 5; // Destination South East } else { npctalk "Out of the field! I am going to the corner."; set $@destinationType, 3; // Destination North West } // It's the blue team (attackers) that now possess the ball: set $@teampossessingballID, $@blueteamID; } else if ($@ActiveteamID==$@blueteamID) { // If the ball gets kicked by a player from the attacking team, send the ball in front of the goal npctalk "Out of the field! I am going in front of the Red Team's goal."; set $@destinationType, 7; // Destination East Goal // It's the red team (defenders) that now possess the ball: set $@teampossessingballID, $@redteamID; } else end; stopnpctimer; initnpctimer; end; } else if ($@mapxNPC<=12) { // T h e b a l l i s o n t h e w e s t s i d e // Check if we are in the left-side goal if ((53<=$@mapyNPC)&&($@mapyNPC<=59)) { mapannounce "ball2", " "+$@Activeplayers$+" from the "+getpartyname($@redteamID)+" party has scored a goal for the Red Team!",bc_yellow; if ($@ActiveteamID==$@redteamID) { specialeffect 92; mapannounce "ball2", " Nice shot! "+$@Activeplayers$+" you made red team proud xD!",bc_blue; atcommand "@npctalk Red Fans#fred9,I love you, Red Team!"; atcommand "@npctalk Red Fans#fred8,Keep up the good work!"; atcommand "@npctalk Red Fans#fred7,Nice job!"; atcommand "@npctalk Red Fans#fred6,I know you can do it, you didnt dissapoint me~"; atcommand "@npctalk Red Fans#fred5,Yee haw!"; atcommand "@npctalk Red Fans#fred4,Blue Team..YOU SUCK!"; atcommand "@npctalk Red Fans#fred3,Red Team is the best!"; } else { mapannounce "ball2", "SWT!!! "+$@Activeplayers$+" has just shot an own goal!!! ERWWWW..."+$@Activeplayers$+"! ",bc_blue; mapannounce "ball2", "Blue teams supporters are angry at "+$@Activeplayers$+" that made blue team ashamed =< and the red teams supporters are laughing out loud! HAHAHAAHA!!!!!",bc_blue; } npctalk "Goal! I'll return in the middle of the field."; set $@score_red_match, $@score_red_match +1; set $@destinationType, 1; // Destination middle of the field set $@teampossessingballID, $@blueteamID; stopnpctimer; initnpctimer; end; } mapannounce "ball2", " "+$@Activeplayers$+" has sent the Poring Ball out of the field!",0xFF0000; mapannounce "ball2", "The other team will be given 5 seconds to kick the ball in, otherwise both team can kick the ball.",0xFF0000; set $@isballonfield,1; if ($@ActiveteamID==$@blueteamID) { // If the ball gets kicked by a player from the defending team, send the ball in the right corner: if ($@mapyNPC<=56) { npctalk "Out of the field! I am going to the corner."; set $@destinationType, 4; // Destination South East } else { npctalk "Out of the field! I am going to the corner."; set $@destinationType, 2; // Destination North West } // It's the red team (attackers) that now possess the ball: set $@teampossessingballID, $@redteamID; } else if ($@ActiveteamID==$@redteamID) { // If the ball gets kicked by a player from the attacking team, send the ball in front of the goal npctalk "Out of the field! I am going in front of the Blue Team's goal."; set $@destinationType, 6; // Destination West Goal // It's the blue team (defenders) that now possess the ball: set $@teampossessingballID, $@blueteamID; } else end; stopnpctimer; initnpctimer; end; } else if (($@mapyNPC>=89)||($@mapyNPC<=23)) { // T h e b a l l i s o n ( e i t h e r N o r t h o r S o u t h s i d e ) mapannounce "ball2", " "+$@Activeplayers$+" has sent the Poring Ball out of the field!",0xFF0000; mapannounce "ball2", "The other team will be given 5 seconds to kick the ball in, otherwise both team can kick the ball.",0xFF0000; set $@isballonfield,1; if ($@ActiveteamID==$@redteamID) && ($@bothteam != 0) { set $@teampossessingballID, $@blueteamID; npctalk "Poring for the Blue Team."; donpcevent "TimesOut::OnTimes"; } else if ($@ActiveteamID==$@blueteamID) && ($@bothteam != 0) { set $@teampossessingballID, $@redteamID; npctalk "Poring for the Red team."; donpcevent "TimesOut::OnTimes"; } end; } } // Preparation for the next movement set $@distance,$@distance-1; if ($@distance>0) { stopnpctimer; initnpctimer; } end; } - script TimesOut -1,{ OnTimes: stopnpctimer; initnpctimer; end; OnTimer24000: mapannounce "ball2", "Enough time given. Now either team can kick the ball.",0xFF0000; set $@bothteam,0; end; } // ******************************************************************* // Others NPCs // ******************************************************************* ball2,12,52,6 script Red Flag#fred1 722,{ end; } ball2,12,60,6 script Red Flag#fred2 722,{ end; } ball2,8,60,6 script Red Fans#fred3 1096,{ end; } ball2,8,52,6 script Red Fans#fred4 1096,{ end; } ball2,8,56,6 script Red Fans#fred5 1096,{ end; } ball2,10,60,6 script Red Fans#fred6 1096,{ end; } ball2,10,52,6 script Red Fans#fred7 1096,{ end; } ball2,8,54,6 script Red Fans#fred8 1096,{ end; } ball2,8,58,6 script Red Fans#fred9 1096,{ end; } ball2,9,70,6 script Red Bench Player#1 882,{ npctalk "Aww..I just can sit here watch only T_T"; end; } ball2,8,41,6 script Red Bench Player#2 882,{ npctalk "I wish i could go in and play..."; end; } ball2,9,29,8 script Red Audience#1 708,{ npctalk "Wow, what an interesting match!"; end; } ball2,9,83,8 script Red Audience#2 708,{ npctalk "Nice shot! Good defence! Good pass! Awesome skill!"; end; } ball2,35,92,4 script Red Cheer Leader#1 700,{ npctalk "Cheer out loud for RED TEAM! GoGoGo RED TEAM!!! xD"; end; } ball2,92,92,4 script Red Cheer Leader#2 700,{ npctalk "Anyway if you doesnt have anything to do..please cheer out loud for red team! GoGoGo Red TEAM!!! xD"; end; } ball2,60,92,4 script Poring Soccer Refree 109,{ npctalk "Foul!!! Yellow Card! Dont do that again!"; sleep2 5000; npctalk "Foul!!! Red Card! You are out of the match!"; end; } ball2,5,56,6 script Game Ticket Dealer#r 1904,{ npctalk "Come and exchange your game ticket here!~"; mes "Hola, what brings you here my dear?"; next; mes "Hmm?"; menu "I heard that I can exchange something special with this ticket..",PSE_Exchange,"You look mysterious..anyway just by passing haha!",PSE_nvm; PSE_Exchange: if(!countitem($@ticket)){ mes "LOL...WHAT TICKET!? U DONT HAVE IT ZZZ"; close; } mes "OHHHhhh you have this ticket! WOW!"; mes "Ya you can exchange something special with this ticket but there is one thing you must remember that you can only exchange once!"; next; mes "So are you sure to exchange?"; switch(select("Yes and make it quick pls..","Only exchange once? Nvm then..I keep it 1st.")) { case 1: delitem $@ticket,1; mes "Here you go!"; getitem $@hatID[1],1; next; mes "Wear it and it symbolize your support towards Red Team!"; close; end; case 2: mes "Alright see ya again!"; close; end; } PSE_nvm: mes "Hmm why i look mysterious my dear?"; next; mes "Do you want some cookies? my dear dear...oh nvm then~"; close; end; } ball2,108,52,2 script Blue Flag#fblue1 722,{ end; } ball2,108,60,2 script Blue Flag#fblue2 722,{ end; } ball2,112,56,2 script Blue Fans#fblue3 1388,{ end; } ball2,112,60,2 script Blue Fans#fblue4 1388,{ end; } ball2,112,52,2 script Blue Fans#fblue5 1388,{ end; } ball2,110,60,2 script Blue Fans#fblue6 1388,{ end; } ball2,110,52,2 script Blue Fans#fblue7 1388,{ end; } ball2,112,58,2 script Blue Fans#fblue8 1388,{ end; } ball2,112,54,2 script Blue Fans#fblue9 1388,{ end; } ball2,111,41,2 script Blue Bench Player#1 881,{ npctalk "Aww..I just can sit here watch only T_T"; end; } ball2,111,70,2 script Blue Bench Player#2 881,{ npctalk "I wish i could go in and play..."; end; } ball2,111,83,3 script Blue Audience#1 862,{ npctalk "Wow, what an interesting match!"; end; } ball2,111,27,3 script Blue Audience#2 862,{ npctalk "Nice shot! Good defence! Good pass! Awesome skill!"; end; } ball2,92,20,0 script Blue Cheer Leader#1 777,{ npctalk "Cheer out loud for BLUE TEAM! GoGoGo Blue TEAM!!! xD"; end; } ball2,38,20,0 script Blue Cheer Leader#2 777,{ npctalk "Anyway if you doesnt have anything to do..please cheer out loud for blue team! GoGoGo Blue TEAM!!! xD"; end; } ball2,115,56,2 script Game Ticket Dealer#b 1904,{ npctalk "Come and exchange your game ticket here!~"; mes "Hola, what brings you here my dear?"; next; mes "Hmm?"; menu "I heard that I can exchange something special with this ticket..",PSE_Exchange,"You look mysterious..anyway just passing by!",PSE_nvm; PSE_Exchange: if(countitem($@ticket)<1){ mes "LOL...WHAT TICKET!? U DONT HAVE IT ZZZ"; close; } mes "OHHHhhh you have this ticket! WOW!"; mes "Ya you can exchange something special with this ticket but there is one thing you must remember that you can only exchange once!"; next; mes "So are you sure to exchange?"; switch(select("Yes and make it quick pls..","Only exchange once? Nvm then..I keep it 1st.")) { case 1: delitem $@ticket,1; mes "Here you go!"; getitem $@hatID[2],1; next; mes "Wear it and it symbolize your support towards Blue Team!"; close; end; case 2: mes "Alright see ya again!"; close; end; } PSE_nvm: mes "Hmm why i look mysterious my dear?"; next; mes "Do you want some cookies? my dear~"; close; end; } ball2,60,20,8 script Field Assistant 914,{ mes "[Field Assistant]"; mes "Hi, what do you want?"; next; if ((getcharid(1)!=$@redteamID) && (getcharid(1)!=$@blueteamID)) { mes "You are either just a spectator here, or you are not one of them!"; mes "Therefore, you cant use this npc!!!"; close; end; } if (getgmlevel()<70) { switch(select("Switch the ball","Change the weather","Request time out","Trigger Absolute Defense","I dont want to play anymore!")) { case 1: mes "You want to switch a different ball?"; next; mes "Which ball would you like to use?"; switch(select("Green Nike ball","Orange Adidas ball","Metal Machine ball","Blue Sports ball","Purple Enchanted ball","Lightblue Wing ball","Ghost Freak ball","Hard Rock ball","Default-Pink Gloomy ball")) { case 1: set $@switchball[1],1; close2; donpcevent "Ball::OnBallSwitch"; end; case 2: set $@switchball[2],1; close2; donpcevent "Ball::OnBallSwitch"; end; case 3: set $@switchball[3],1; close2; donpcevent "Ball::OnBallSwitch"; end; case 4: set $@switchball[4],1; close2; donpcevent "Ball::OnBallSwitch"; end; case 5: set $@switchball[5],1; close2; donpcevent "Ball::OnBallSwitch"; end; case 6: set $@switchball[6],1; close2; donpcevent "Ball::OnBallSwitch"; end; case 7: set $@switchball[7],1; close2; donpcevent "Ball::OnBallSwitch"; end; case 8: set $@switchball[8],1; close2; donpcevent "Ball::OnBallSwitch"; end; case 9: set $@switchball[9],1; close2; donpcevent "Ball::OnBallSwitch"; end; } case 2: switch(select("Sakura","Leaves","Clouds","Fog","Snow","Day","Night","Default(Normal)")) { case 1: if ($@weather==1) { mes "I am sorry, another weather is functioning"; next; mes "Please set it to default and then try change again, thank you^^"; close; end; } atcommand "@sakura"; set $@weather,1; close; end; case 2: if ($@weather==1) { mes "I am sorry, another weather is functioning"; next; mes "Please set it to default and then try change again, thank you^^"; close; end; } atcommand "@leaves"; set $@weather,1; close; end; case 3: if ($@weather==1) { mes "I am sorry, another weather is functioning"; next; mes "Please set it to default and then try change again, thank you^^"; close; end; } atcommand "@clouds"; set $@weather,1; close; end; case 4: if ($@weather==1) { mes "I am sorry, another weather is functioning"; next; mes "Please set it to default and then try change again, thank you^^"; close; end; } atcommand "@fog"; set $@weather,1; close; end; case 5: if ($@weather==1) { mes "I am sorry, another weather is functioning"; next; mes "Please set it to default and then try change again, thank you^^"; close; end; } atcommand "@snow"; set $@weather,1; close; end; case 6: if ($@weather==1) { mes "I am sorry, another weather is functioning"; next; mes "Please set it to default and then try change again, thank you^^"; close; end; } atcommand "@day"; set $@weather,1; close; end; case 7: if ($@weather==1) { mes "I am sorry, another weather is functioning"; next; mes "Please set it to default and then try change again, thank you^^"; close; end; } atcommand "@night"; set $@weather,1; close; end; case 8: set $@weather,0; atcommand "@clearweather"; atcommand "@refresh"; close; end; } case 3: if ($@state_match!=3) { mes "The match has'nt start yet!"; close; } if ($@timedelay==3) { mes " I am sorry but you cant use this function anymore, because it already been used before (due to prevent spaming)"; close; } if(getpartyleader(getcharid(1),2) != getcharid(0)){ mes "I am sorry, Only party leaders are allow to use this function!"; close; end; } mes "Are you sure you want to request match time out for 1 minute?"; next; mes "^FF3333PLEASE NOTE THAT YOU ARE ALLOWED TO USE ONCE ONLY!!!^000000"; mes "^FF3333PLEASE NOTE THAT YOU ARE ALLOWED TO USE ONCE ONLY!!!^000000"; mes "^FF3333PLEASE NOTE THAT YOU ARE ALLOWED TO USE ONCE ONLY!!!^000000"; switch(select("Yes:No")) { case 1: if ($@timedelay==0) { mes "Alright your request has submitted"; close2; if (getcharid(1)==$@redteamID) { mapannounce "ball2", " "+getpartyname($@redteamID)+" Team has request a match time out for 1 minute!",bc_map; } if (getcharid(1)==$@blueteamID) { mapannounce "ball2", " "+getpartyname($@blueteamID)+" Team has request a match time out for 1 minute!",bc_map; } mapannounce "ball2", "Everyone now can do whatever things you want to do such as switch ball, change weather, or plan your strategy!",bc_blue; goto L_Timeout; close2; } mes "I'm sorry, time out request are not available now!"; close; case 2: mes "Alright, come back when you need me~"; close; } case 4: if (getcharid(1)==$@redteamID) { if (.helpdelay < gettimetick(2) ) { dispbottom "You triggered the absolute defense system!"; mapannounce "ball2", " "+getpartyname($@redteamID)+" Team has triggered the defense system!",bc_map; specialeffect2 97; sleep2 900; setarray .@x[0], 106, 105, 104, 103, 102, 101, 100, 99, 99, 99, 99, 99, 99, 99, 99, 100, 101, 102, 103, 104, 105, 106; setarray .@y[0], 60, 60, 60, 60, 60, 60, 60, 59, 58, 57, 56, 55, 54, 53, 52, 52, 52, 52, 52, 52, 52, 52; for (set .@i, 0; .@i < getarraysize(.@x); set .@i, .@i + 1) { set .@idbarrier, bg_monster(0,"ball2",.@x[.@i],.@y[.@i]," ",1905); setwall "ball2",108,59,8,2,0,"PWall21"; setwall "ball2",99,53,8,0,0,"PWall22"; setwall "ball2",108,53,8,2,0,"PWall23"; addtimer 15000, "Field Assistant::Ondelwall"; } set .helpdelay, gettimetick(2) + 299; } else { dispbottom "No help at the moment. Wait "+((.helpdelay - gettimetick(2)) + 1)+" seconds."; close; } } if (getcharid(1)==$@blueteamID) { if (.helpdelay < gettimetick(2) ) { dispbottom "You triggered the absolute defense system"; mapannounce "ball2", " "+getpartyname($@blueteamID)+" Team has triggered the defense system!",bc_map; specialeffect2 97; sleep2 900; setarray .@x[0], 14, 15, 16, 17, 18, 19, 20, 21, 21, 21, 21, 21, 21, 21, 21, 20, 19, 18, 17, 16, 15, 14; setarray .@y[0], 60, 60, 60, 60, 60, 60, 60, 59, 58, 57, 56, 55, 54, 53, 52, 52, 52, 52, 52, 52, 52, 52; for (set .@i, 0; .@i < getarraysize(.@x); set .@i, .@i + 1) { set .@idbarrier, bg_monster(0,"ball2",.@x[.@i],.@y[.@i]," ",1905); setwall "ball2",19,52,12,2,0,"PWall24"; setwall "ball2",20,53,8,0,0,"PWall25"; setwall "ball2",19,60,12,2,0,"PWall26"; addtimer 15000, "Field Assistant::Ondelwall"; } set .helpdelay, gettimetick(2) + 299; } else { dispbottom "No help at the moment. Wait "+((.helpdelay - gettimetick(2)) + 1)+" seconds."; close; } } case 5: mes "Are you sure you wanna leave?"; switch(select("Cancel","Yes")) { case 1: close; case 2: goto OnLeave; close; end; } Ondelwall: atcommand "@killmonster"; delwall "PWall21"; delwall "PWall22"; delwall "PWall23"; delwall "PWall24"; delwall "PWall25"; delwall "PWall26"; mapannounce "ball2", "Defense system has shattered!",bc_map; end; } } switch(select("Switch the ball","Cancel the match","Give a point to the Red Team","Give a point to the Blue Team","Leave")) { case 1: mes "You want to switch a different ball?"; next; mes "Which ball would you like to use?"; switch(select("Green Nike ball","Orange Adidas ball","Metal Machine ball","Blue Sports ball","Purple Enchanted ball","Lightblue Wing ball","Ghost Freak ball","Hard Rock ball","Suicide Bomb ball","Default-Pink Gloomy ball")) { case 1: set $@switchball[1], 1; close2; donpcevent "Ball::OnBallSwitch"; end; case 2: set $@switchball[2], 1; close2; donpcevent "Ball::OnBallSwitch"; end; case 3: set $@switchball[3], 1; close2; donpcevent "Ball::OnBallSwitch"; end; case 4: set $@switchball[4], 1; close2; donpcevent "Ball::OnBallSwitch"; end; case 5: set $@switchball[5], 1; close2; donpcevent "Ball::OnBallSwitch"; end; case 6: set $@switchball[6], 1; close2; donpcevent "Ball::OnBallSwitch"; end; case 7: set $@switchball[7], 1; close2; donpcevent "Ball::OnBallSwitch"; end; case 8: set $@switchball[8], 1; close2; donpcevent "Ball::OnBallSwitch"; end; case 9: set $@switchball[9], 1; close2; donpcevent "Ball::OnBallSwitch"; end; case 10: set $@switchball[10], 1; close2; donpcevent "Ball::OnBallSwitch"; end; } case 2: if ($@state_match == 3) { set $@blueteamID, 0; set $@redteamID, 0; set $@redconfirmation, 0; set $@blueconfirmation, 0; set $@state_match, 0; set $@isballonfield, 0; set $@teampossessingballID, 0; donpcevent "TimerMatchcancellation::OnMatchcancellation"; } else mes "No match is in progress."; break; case 3: if ($@state_match == 3) { mapannounce "ball2", " "+strcharinfo(0)+ " has added a point for the Red Team!",bc_blue; set $@score_match_rouge, $@score_match_rouge+1; } else mes "No match is in progress."; break; case 4: if ($@state_match == 3) { mapannounce "ball2", " "+strcharinfo(0)+ " has added a point for the Blue Team!",bc_blue; set $@score_blue_match, $@score_blue_match+1; } else mes "No match is in progress."; break; case 5: goto OnLeave; break; } switch(select("Leave","Cancel")) { case 1: goto OnLeave; break; case 2: break; } close; OnLeave: warp "quiz_02",350,374; close; L_Timeout: set $@timedelay,1; sleep 50000; mapannounce "ball2", "Alright! times up! I believe everyone have rested enough.. Get ready to continue the match!",bc_blue; sleep 5000; mapannounce "ball2", "MATCH CONTINUE!!! Everyone GO GO GO!! ",bc_map; set $@timedelay,3; close; end; } quiz_02,335,384,5 script Game Hoster#hjPb1 69,{ cutin "god_kukur01",2; mes "^BF0073[Game Hoster]^000000"; mes "Do you wish to leave or stay in the Waiting Room?"; next; set @palette, getlook(7); menu "I want my clothes back.",OnReturnShirt, "Yes, I want to return to town.",OnLeaveRoom,"No, I wish to stay.",-; close2; cutin "",255; end; OnReturnShirt: cutin "",255; cutin "god_kukur03",2; mes "^BF0073[Game Hoster]^000000"; if ((@palette == $paletteRed) ||(@palette == $paletteBlue)) { mes "Well I will send you back, and here is your clothes!"; setlook 7, savePalette; } else { mes "You're not already playing Poring Ball! Are you trying to steal someones clothes!?"; mes "Get out of my sight ! Out !!!"; emotion e_omg; } close2; cutin "",255; end; OnLeaveRoom: cutin "",255; if ((@palette == $paletteRed) ||(@palette == $paletteBlue)) { cutin "god_kukur03",2; mes "^BF0073[Game Hoster]^000000"; mes "Before you leave, I will give you back your clothing!"; setlook 7, savePalette; next; cutin "",255; } savepoint "prontera",156,187; warp "prontera",156,187; end; } // map football field ball2 mapflag noicewall //ball2 mapflag pvp ball2 mapflag pvp_noguild ball2 mapflag nomemo ball2 mapflag noteleport ball2 mapflag nowarp ball2 mapflag nosave SavePoint ball2 mapflag nopenalty ball2 mapflag nobranch ball2 mapflag noexp // map for team constitution quiz_02 mapflag noskill quiz_02 mapflag nomemo quiz_02 mapflag nobranch quiz_02 mapflag nopenalty quiz_02 mapflag noexp quiz_02 mapflag nowarp quiz_02 mapflag noicewall If anyone can help, I would really appreciate it! Dimension-RO 2023-11-21 11-36-02.mp4
  2. View File Battleground Extended 2020 ! With Bomberman/Poring Ball Mystic Project is about to open its last opus. For the occasion, Mystic Project has decided to make a gift to the community of rAthena and release one of its contents ! We've chosen the Battleground Extended, a memorable feature created by the eAmod and adapted for the new version of rAthena 2020. What are Battleground Extended ? They are an upgrade of the official Battleground made by the eAmod years ago and enhanced overtime. Battleground guide Name Description Flavius Same as official. The Goal is to destroy each's crystal. Flavius Capture The Flag The objective of the Flavius Battle CTF is to score 3 points before your enemy, by capture their Flag. To capture a Flag you need to take the enemy flag, and bring it to your base flag. If your base flag is captured too, you need to kill the flag carrier and take the flag back to your base. Flavius Death Match Each team has a certain number, Kill all the enemy players to let their Team without points. Protect your army. Flavius Stone Control Take the Stones in the middle of the battlefield and put in on your base, in the Stone Points. Each Stone will give points to your team. First team reach 99 points wins the game. Protect your stones from to be captured by the enemy. Tierra Eye of Storm There are two bases, North and South which teams can capture by holding position on the Base more than the other team. Each base will give you points each 5 seconds of Domination. If your Team control both bases the amount of points increases. To get additional points, in the middle there is a Flag spawn, capture it and put it on any of your team Bases. The first Team reach 99 points wins the match. Tierra Bossnia Attack the enemy base and destroy each MVP Guardian. To do damage to the guardian your team must capture the Balance Flag in the middle base. Each team have 5 guardian to be protected or killed. Tierra Domination There are three bases, North, Center and South which teams can capture by holding position on the Base more than the other team. Each base will give you points each 5 seconds of Domination. The first Team reach 99 points wins the match. Krieger Von Midgard (KVM) Same as official, regular PVP. Double Inferno There are 2 teams in the battlefield, your team and the opposite enemies. Kill the enemy players, collect the skulls and bring them to the Sacrifice Totem to win points. You can collect your own team skulls and bring then to your Sacrifice Totem to avoid other teams to score but it won't count as points. If you get killed all your skulls will be drop to the floor, including your own skull. First Team to get 80 points wins the battle. Conquest If you are Attacking, destroy the enemy defenses and it's Flag. If you are Defending, protect your castle defenses and the Flag. Rush Fight to capture the Castle and organize your team to defend it. If you fail on the first capture, kill the defender and take it for your team. Poring Ball It is a soccer game, a poring (the ball) will be in the middle of the field. The match lasts 5min. The team that has the most goals win the game. Super Bomberman The classic game specially made in Ragnarok Online. The goal is to defeat the enemies by putting bombs that will explode on them. It is a 2vs2 version of the game. Peco Peco Racer Coming soon... Mario Kart - RO version : New Battleground Queue System Battleground Commands @joinbg will warp you only to the battleground room. (Use interface UI Battleground to join any running BG or create one) @leavebg will warp you out of the the current battleground you're in. @listenbg display or not the battleground explanations. @order is only for the leader, an huge announce will be displayed to the team. @reportafk is only for the leader, expulsing someone who is AFK. @bginfo will display all curent running BGs + amount of players + scores for each team and remaining time of the BG Battleground Skills @bgskill is used by the leader. I left it there as a memory but you better use the guild interface alt + g -> guild skill tree The leader can use the following skills: - Emergency Recall: Warp everyone from the team to the leader. - Battle Orders: All guild members visible on the guild leader screen will receive +5 STR, DEX, INT. (Now having a status icon on the right) - Regeneration: All guild members visible on the guild leader screen will increase their HP and SP regen rate. (Now having a status icon on the right) - Restore: All guild members visible on the guild leader screen will have their HP and SP restored to 90% of the respective maximum. - Chargeshout Flag: The leader will summon a guild flag. - Chargeshout Beating: Anyone in the guild can use this skill, it will warp to the guild flag IF you are on the same map as the flag. - Emergency Move: All guild members visible on the guild leader screen will receive the effect of speed potion, increasing walking speed by 25%. Kill Count Each person killed on a battlefield will be counted in your guild information. This is like a rank. In bg_common.txt, you will find this. If you already use OnPCKillEvent, I recommend you to remove this code and add it to yours. Red / Blue Teams Upon your arrival on the battlefield, you are going to see yourself in a clan (alt + g) and a guild (ctrl + g). Blue Team : http://mysticprojectro.com/wiki/images/d/d1/Clan_emblem01.jpg Red Team : http://mysticprojectro.com/wiki/images/a/a9/Clan_emblem02.jpg Each team-mate will have this emblem by their character's name. Enemies will be displaying the opposite emblem. Some battlefields will change your cloth dye as well for the attributed color but don't worry, you will get yours back as soon as the game is over. You can communicate with your team through the guild chat. When you leave the battlefield, the clan will be removed and you will be back in your actual guild. Battleground Happy Hours Battleground happy hours happen everyday from 4pm to 8pm during which, rewards obtained are increased by 60%. (Configurable in npc/battleground/bg_common.txt) Battleground Rewards Telma/Erundek NPCs from the official battleground are there to exchange Consumables / Stuff. However, some of you rather customize the rewards. It's up to you to remove Telma/Erundek. If you want to customize Rewards, here is a frame (located in bg_common.txt) made to buy stuff directly with badges. Poring Ball Youtube Video Demonstration : Ragnarok Online - DaRO : BattleGround Extended + - YouTube The original Poring Ball Map was created by us 14 years ago. (On the left). At the time, we had poor experience in mapping so my apologies if you don't find it attractive. However, you can always purchase the beautiful rework done by Olrox (on the right): https://olroxgraphics.com/index.php?/store/product/107-soccer-stadium/ Depending on which map you will pick, you need to configurate the Poring Ball. I assume you already have Olrox's map so by default, it is this configuration. If you want the free map that is included in this pack, you need to comment /* */ Olrox Poring Ball Map and remove the comment of Grenat Poring Ball Map (See orange sign) Bomberman Video Demonstration : Super Bomberman Ragnarok Online YouTube Video I've read a lot of times people asking about it ! We are releasing the new Bomberman Battleground Version with 3 bomberman maps (two of them are made by us) In bg_bomberman.txt, you will find this code. Make sure to remove it and add it to your OnPCStatCalcEvent, otherwise just leave it there. Some newer rAthena version doesn't have OnPCStatCalcEvent anymore, you may need to reinstall it. Installation : In this package, you will find : - BattlegroundExtended.diff : You will need to apply this patch. (cmd -> cd rathena -> git apply BattlegroundExtended.diff ) It has been created in 2020 and work with the latest rAthena. (Possibly working on previous version from 2018+). - NPC folder: I strongly recommend to delete all BG NPCs and only install the ones that are in this folder. It is compatible with the new BG Queue Systeme. Please review Poring Ball.txt to configurate your poring ball as well as bg_common for the happy hour rate. - DB: I did put items in txt and yml files since I don't know which version you guys are using. DO NOT copy paste in your db folder. Only take what's inside each files. - Client: Contains items/maps/texture/files/lua (for the new BG queue system)/bomberman music etc... Extract the contents inside your RO client folder. This patch modifies a lot of files, you may need to install the diff manually depending on your rAthena version. Once installed, please recompile your map_cache with the client data installed in the directory/grf the server reads to compile it. Configuration : Your server might be different than ours. This is why, it is important to configurate well the system. conf/battle/battleground.conf -> Search for battleground eAmod and configure them. db/battleground.xml -> "Color" represents the clothes palette given upon arrival on the battlefield. The player's Palette will come back to the original one when the BG is over. If you don't want players to have different cloth color, just put 0 or do not put anything at all. In our server, Color : 6 is blue, and 22 is red. Therefore, this is our configuration. I let you configure yours. Additional New Script Commands : * getnpcinfo <type>{,<char_id>} type: NPC_X: X, NPC_Y: Y * setporingball; (When activated, it would be like an OnClickedCell, almost ;), it calls a script for the poring ball (Or other things if you want to add things there). * getporingballx() / getporingbally(); (Get coordination of a clicked cell) * removeporingball; (Remove poring ball mode (Clickable cell calling a script) * getunitdir <unit_id/account_id>; (Get direction the unit is looking) * ispcsit <account_id> (Get information if a pc is sit or not) * unitpush <unit_id/account_id>,<dir>,<cells>; (Push (knockback) a specific target in a specific direction) * areaeffect( effect id, x, y); Any Questions ? You can contact me on Discord: Grenat#5220 for support regarding the installation. Support post : Release: Battleground Extended 2020 ! With Bomberman/Poring Ball - Source Releases - rAthena Team Mystic Project. Submitter grenat50 Submitted 02/04/2021 Category Source Modifications Video Content Author Grenat
  3. Anyone can modify this script of @Euphy and @AnnieRuru //===== rAthena Script ======================================= //= Private MVP & Branch Room //===== By: ================================================== //= AnnieRuru //===== Current Version: ===================================== //= 1.0 //===== Compatible With: ===================================== //= rAthena Project //===== Description: ========================================= //= Allows players to rent an MVP room for personal use, //= or for a party or guild. //===== Additional Comments: ================================= //= 1.0 First version, edited. [Euphy] //============================================================ prontera,166,206,4 script Private MVP Room 71,{ mes "[Private MVP Room]"; mes "Please select a private MVP room."; if (getvariableofnpc(.rentcost, "MVP Summoner")) mes "The cost to rent a room for " + getvariableofnpc(.timeout, "MVP Summoner") + " minutes is " + callfunc("F_InsertComma", getvariableofnpc(.rentcost, "MVP Summoner")) + " zeny."; else mes "You can only use the room for only " + getvariableofnpc(.timeout, "MVP Summoner") + " minutes."; mes " "; for (.@i = 1; .@i <= 8; .@i++) if (getvariableofnpc(.renttime[.@i], "MVP Summoner")) mes "Room #" + .@i + " = " + .color$[.type[.@i]] + .whoinuse$[.@i] + "^000000"; next; .@room = select( "MVP Room 1 [" + getmapusers("06guild_01") + "]", "MVP Room 2 [" + getmapusers("06guild_02") + "]", "MVP Room 3 [" + getmapusers("06guild_03") + "]", "MVP Room 4 [" + getmapusers("06guild_04") + "]", "MVP Room 5 [" + getmapusers("06guild_05") + "]", "MVP Room 6 [" + getmapusers("06guild_06") + "]", "MVP Room 7 [" + getmapusers("06guild_07") + "]", "MVP Room 8 [" + getmapusers("06guild_08") + "]"); if (getvariableofnpc(.renttime[.@room], "MVP Summoner")) { if (.inuseid[.@room] == getcharid(.type[.@room])) { warp "06guild_0" + .@room, 50,46; close; } else { mes "[Private MVP Room]"; mes "This room is reserved for "; mes .color$[.type[.@room]] + .whoinuse$[.@room] + "^000000."; mes "Please select another."; close; } } mes "[Private MVP Room]"; mes "Reserve this room for..."; next; set .@type, select("For my party members", "For my guild members", "For personal account use"); if (!getcharid(.@type)) { mes "[Private MVP Room]"; mes "You do not own a " +((.@type == 1)? "Party" : "Guild") + "."; close; } else if (Zeny < getvariableofnpc(.rentcost, "MVP Summoner")) { mes "You don't have enough zeny to rent a room."; close; } else if (getvariableofnpc(.renttime[.@room], "MVP Summoner")) { mes "[Private MVP Room]"; mes "I'm sorry, somebody else has already registered this room faster than you."; close; } for (.@i = 1; .@i <= 8; .@i++) { if ((getvariableofnpc(.renttime[.@i], "MVP Summoner")) && .@type == .type[.@i] && getcharid(.@type) == .inuseid[.@i]) { mes "[Private MVP Room]"; mes "You already rented Room#" + .@i + ". Use that room instead."; close; } } set .type[.@room], .@type; set .inuseid[.@room], getcharid(.@type); set .whoinuse$[.@room], strcharinfo((.@type == 3)? 0 : .@type); Zeny -= getvariableofnpc(.rentcost, "MVP Summoner"); warp "06guild_0" + .@room, 50,46; killmonsterall "06guild_0" + .@room; donpcevent "MVP Summoner#" + .@room + "::OnEnterMap"; close; OnInit: .color$[1] = "^EE8800"; // party color .color$[2] = "^70CC11"; // guild color .color$[3] = "^0000FF"; // account color end; } - script MVP Summoner -1,{ mes "[MVP Summoner]"; mes "Time left: " + callfunc("Time2Str", .renttime[atoi(strnpcinfo(2))] + .timeout * 60); mes "Hi, what can I do for you?"; next; setarray .mobsx[0],8,50,91,50; setarray .mobsy[0],50,91,50,8; set .mobsxy, rand(0,3); switch (select(.menu$)) { case 1: if (mobcount("this", strnpcinfo(3) + "::OnMobDead")) { mes "[MVP Summoner]"; mes "I cannot summon another MVP when there are monsters around."; close; } else if (.mvpcost) { mes "[MVP Summoner]"; mes "The cost to summon an MVP is " + callfunc("F_InsertComma", .mvpcost) + " zeny."; next; set .@menu, select(.mvpid_menu$) -1; mes "[MVP Summoner]"; if (Zeny < .mvpcost) { mes "You don't have enough zeny to summon an MVP."; close; } } else { set .@menu, select(.mvpid_menu$) -1; mes "[MVP Summoner]"; } mes "Please get ready."; close2; if (Zeny < .mvpcost) end; Zeny -= .mvpcost; monster "this", .mobsx[.mobsxy], .mobsy[.mobsxy], "--ja--", .mvpid[.@menu], 1, strnpcinfo(3) + "::OnMobDead"; end; case 2: if (mobcount("this", strnpcinfo(3) + "::OnMobDead")) { mes "[MVP Summoner]"; mes "I cannot summon another mini-boss when there are monsters around."; close; } else if (.bosscost) { mes "[MVP Summoner]"; mes "The cost to summon a mini-boss is " + callfunc("F_InsertComma", .bosscost) + " zeny."; next; set .@menu, select(.bossid_menu$) -1; mes "[MVP Summoner]"; if (Zeny < .bosscost) { mes "You doesn't have enough zeny to summon a mini-boss."; close; } } else { set .@menu, select(.bossid_menu$) -1; mes "[MVP Summoner]"; } mes "Please get ready."; close2; if (Zeny < .bosscost) end; Zeny -= .bosscost; monster "this", .mobsx[.mobsxy], .mobsy[.mobsxy], "--ja--", .bossid[.@menu], 1, strnpcinfo(3) + "::OnMobDead"; end; case 3: mes "[MVP Summoner]"; mes "Great Demon Baphomet could enter invincible state, meaning you can't hurt them."; mes "Do you want to remove it?"; next; if (select("Yes:No") == 1) { if (Zeny < .removecost) { mes "[MVP Summoner]"; mes "You doesn't have enough zeny to remove Great Demon Baphomet's invincible state."; mes "Good Luck!"; close; } Zeny -= .removecost; getmapxy .@map$, .@x, .@y; areamobuseskill .@map$,50,50,50,1929,"NPC_INVINCIBLEOFF",1,0,0,ET_HELP,0; mes "[MVP Summoner]"; mes "Done!"; mes "Good luck on defeating them!"; close; } mes "[MVP Summoner]"; mes "Okay then"; close; case 4: mes "[MVP Summoner]"; mes "Are you sure you want to leave this room?"; next; if (select("Yes:No") == 1) warp .respawnmap$, .respawnx, .respawny; close; case 5: mes "[MVP Summoner]"; if (getmapusers(strcharinfo(3)) > 1) { mes "There are still some players in this room. Make sure you are the last member in this room to use this option."; close; } mes "Are you sure you want to give up this room?"; if (.rentcost) mes "You will need to pay again to enter this room."; next; if (select("Yes", "No") == 2) close; awake strnpcinfo(0); end; } close; OnMobDead: end; OnEnterMap: .@id = atoi(strnpcinfo(2)); .renttime[.@id] = gettimetick(2); sleep .timeout * 60000; mapwarp strnpcinfo(4), .respawnmap$, .respawnx, .respawny; .renttime[.@id] = 0; killmonsterall strnpcinfo(4); end; OnInit: if (!getstrlen(strnpcinfo(2))) { // Config --------------------------------------------------------------------------------------- // Room rental time, in minutes. // When time runs out, all players inside the room will be kicked out. // Do NOT set this to zero! set .timeout, 60; set .rentcost, 1000000; // Zeny cost for renting a room (0 = free) set .mvpcost, 10000000; // Zeny cost to summon an MVP (0 = free) set .bosscost, 1000000; // Zeny cost to summon a Mini-boss monster (0 = free) set .removecost, 100000; // Zeny cost to remove monster's invincible state (0 = free) // Options setting inside MVP room set .@menu[1], 1; // Turn MVP Summoning On/Off set .@menu[2], 1; // Turn Mini boss Summoning On/Off // Respawn point when players leave the room set .respawnmap$, "prontera"; set .respawnx, 156; set .respawny, 188; setarray .mvpid[0], 1511,// Amon Ra 1647,// Assassin Cross Eremes 1785,// Atroce 1630,// Bacsojin 1039,// Baphomet 1399,// Baphomet 1874,// Beelzebub 2068,// Boitata 1272,// Dark Lord 1719,// Datale 1046,// Doppelgangger 1389,// Dracula 1112,// Drake 1115,// Eddga 1957,// Entweihen Crothen 1418,// Evil Snake Lord 1871,// Fallen Bishop 1252,// Garm 1768,// Gloom Under Night 1086,// Golden Thief Bug 1885,// Gopinich 1929,// Great Demon Baphomet 1990,// Hardrock Mammoth 1649,// High Priest Magaleta 1651,// High Wizard Katrinn 1832,// Ifrit 1492,// Incantation Samurai 1734,// Kiel D-01 1251,// Knight of Windstorm 1779,// Ktullanux 1688,// Lady Tanee 1646,// Lord Knight Seyren 1373,// Lord of Death 1147,// Maya 1059,// Mistress 1150,// Moonlight Flower 1956,// Naght Sieger 2022,// Nidhoggr's Shadow 1087,// Orc Hero 1190,// Orc Lord 1038,// Osiris 1157,// Pharaoh 1159,// Phreeoni 1623,// RSX 0806 1650,// Sniper Shecil 1991,// Tendrilion 1583,// Tao Gunka 1708,// Thanatos 1312,// Turtle General 1751,// Valkyrie Randgris 1685,// Vesper 1648,// Whitesmith Harword 1917,// Wounded Morocc 1658;// Ygnizem setarray .bossid[0], 1096,// Angeling 1388,// Archangeling 1795,// Bloody Knight 1830,// Bow Guardian 1839,// Byorgue 1307,// Cat O' Nine Tail 1283,// Chimera 1302,// Dark Illusion 1582,// Deviling 1091,// Dragon Fly 1093,// Eclipse 1205,// Executioner 1783,// Galion 1592,// Gangster 1681,// Gemini 1120,// Ghostring 1259,// Gryphon 1720,// Hydro 1918,// Incarnation of Morroc 1919,// Incarnation of Morroc 1920,// Incarnation of Morroc 1921,// Incarnation of Morroc 1833,// Kasa 1090,// Mastering 1289,// Maya Purple 1262,// Mutant Dragon 1203,// Mysteltainn 1870,// Necromancer 1700,// Observation 1295,// Owl Baron 1320,// Owl Duke 1702,// Retribution 1831,// Salamander 1701,// Shelter 1754,// Skeggiold (Brown) 1755,// Skeggiold (Blue) 1703,// Solace 1829,// Sword Guardian 1705,// Thanatos Despero 1707,// Thanatos Dolor 1706,// Thanatos Maero 1704,// Thanatos Odium 1204,// Tirfing 1089,// Toad 1092,// Vagabond Wolf 1765;// Valkyrie // Config Ends ------------------------------------------------------------------------ if (!.timeout) set .timeout, 60; .menu$ = .menu$ + (.@menu[1] ? "Summon MVP" : "") + ":"; .menu$ = .menu$ + (.@menu[2] ? "Summon Mini-boss" : "") + ":"; .menu$ = .menu$ + "Remove Invincible State:Leave this room:Give up this room"; if (.@menu[1]) { .@size = getarraysize(.mvpid); for (.@i = 0; .@i < .@size; .@i++) .mvpid_menu$ = .mvpid_menu$ + getmonsterinfo(.mvpid[.@i], MOB_NAME) + ":"; } if (.@menu[2]) { .@size = getarraysize(.bossid); for (.@i = 0; .@i < .@size; .@i++) .bossid_menu$ = .bossid_menu$ + getmonsterinfo(.bossid[.@i], MOB_NAME) + ":"; } } else { mapannounce strnpcinfo(4), "An administrator has refreshed the server. Please re-register this room.", bc_map; mapwarp strnpcinfo(4), .respawnmap$, .respawnx, .respawny; } end; } - shop MVP room#branch -1,604:20000,12103:2000000 06guild_01,50,50,4 duplicate(MVP Summoner) MVP Summoner#1 116 06guild_02,50,50,4 duplicate(MVP Summoner) MVP Summoner#2 116 06guild_03,50,50,4 duplicate(MVP Summoner) MVP Summoner#3 116 06guild_04,50,50,4 duplicate(MVP Summoner) MVP Summoner#4 116 06guild_05,50,50,4 duplicate(MVP Summoner) MVP Summoner#5 116 06guild_06,50,50,4 duplicate(MVP Summoner) MVP Summoner#6 116 06guild_07,50,50,4 duplicate(MVP Summoner) MVP Summoner#7 116 06guild_08,50,50,4 duplicate(MVP Summoner) MVP Summoner#8 116 06guild_01 mapflag nowarpto 06guild_02 mapflag nowarpto 06guild_03 mapflag nowarpto 06guild_04 mapflag nowarpto 06guild_05 mapflag nowarpto 06guild_06 mapflag nowarpto 06guild_07 mapflag nowarpto 06guild_08 mapflag nowarpto 06guild_01 mapflag nomemo 06guild_02 mapflag nomemo 06guild_03 mapflag nomemo 06guild_04 mapflag nomemo 06guild_05 mapflag nomemo 06guild_06 mapflag nomemo 06guild_07 mapflag nomemo 06guild_08 mapflag nomemo 06guild_01 mapflag noteleport 06guild_02 mapflag noteleport 06guild_03 mapflag noteleport 06guild_04 mapflag noteleport 06guild_05 mapflag noteleport 06guild_06 mapflag noteleport 06guild_07 mapflag noteleport 06guild_08 mapflag noteleport 06guild_01 mapflag nosave SavePoint 06guild_02 mapflag nosave SavePoint 06guild_03 mapflag nosave SavePoint 06guild_04 mapflag nosave SavePoint 06guild_05 mapflag nosave SavePoint 06guild_06 mapflag nosave SavePoint 06guild_07 mapflag nosave SavePoint 06guild_08 mapflag nosave SavePoint 06guild_01 mapflag nopenalty 06guild_02 mapflag nopenalty 06guild_03 mapflag nopenalty 06guild_04 mapflag nopenalty 06guild_05 mapflag nopenalty 06guild_06 mapflag nopenalty 06guild_07 mapflag nopenalty 06guild_08 mapflag nopenalty I tried this by @AnnieRuru // ....... if your server has { Overwriting user function [int__] } don't blame me .......... function script int__ { set .@num, atoi(getarg(0)+""); if ( .@num == 0 || .@num >= 2147483647 ) return getarg(0); set .@l, getstrlen(.@num+""); for ( set .@i,0; .@i < .@l; set .@i, .@i + 1 ) { set .@num$, .@num % pow(10,.@i+1) / pow(10,.@i) + .@num$; if ( (.@i+1) % 3 == 0 && .@i+1 != .@l ) set .@num$, ","+ .@num$; } return .@num$; } //===== eAthena Script ====================================== //= Private MVP/Branch Room //===== By: =============================================== //= by ~AnnieRuru~ //===== Current Version: ====================================== //= 1.4a //===== Compatible With: ===================================== //= rathena 16819 //===== Description: ========================================= //= Player can rent MVP room for the player him/herself, for party or for guilds //===== Topic ================================================= //= http://www.eathena.ws/board/index.php?showtopic=187654 //===== Additional Comments: ================================== //= 1.0 //= ---- break the tradition which a script only for a player, or only for a party. //= now 1 room can be use for party and another room can use for guilds. //= ---- timeout feature to prevent player owns the room indefinitely, //= by create a new account and sit/@at'ing inside overnight. //= ---- can disable mvp/boss summon via configuration and becomes a branch room script. //= ---- a double check to prevent players rent all the rooms for himself. //= 1.0a //= ---- fix a critial bug that the time count too fast -_-" //= 1.1 //= ---- added item cost to rent or to summon //= ---- added a config to limit summoning per session //= ---- added flood control option //= 1.2 //= ---- rewrite the waitingroom counter //= ---- optimize the script in a way can add custom summon group //= ---- add config to kill the monsters if the room just being left empty //= ---- add GM can kick room in use //= ---- add able to spawn in numbers //= ---- add limitspawn can configure to negative to limit spawn in that group instead of individual one //= 1.3 //= ---- fix chatroom countdown issue due to rev13269 //= ---- fix a bug if 2 people rent a room at same time, the later 1 will get the room //= ---- add a feature so the GM can know how long the room has rented or abandoned //= 1.4 //= ---- update with new mvp and mini bosses //= ---- fix an exploit if server allow to use @mail, player can send item/zeny away to prevent item/zeny deletion when registering the room //= ---- players die inside mvp room shouldn't lose exp //= 1.4a //= ---- fix this to use in rathena //======================================================== // This is the shop for this Branch room IF you already enable it. Can sell whatever things you want. - shop MVP room#branch -1,604:100000,12103:1000000 - script MVP Summoner -1,{ goto L_Start; OnInit: getmapxy .@map$, .@x, .@y, 1; if ( .@map$ == "" ) { // Config --------------------------------------------------------------------------------------- // Time for rent a room IN MINUTES. When time out, players inside the room will kick out. Do Not set this as 0 set .timeout, 30; // if the room left empty for # minutes, will be treated as give up the room. Do Not set this as 0 set .nobodygiveup, 2; // NOTE : The script only search item OR zeny. if you specify item amount, then it will ask for the item. If item amount is 0, then it will ask for zeny. // the cost to rent a room set .rentitemid, 674; // item id use for rent a room - 674 - mithil coin set .rentitemamount, 0; // amount of items to rent a room set .rentcost, 1000000; // otherwise, zeny cost to rent a room // limit each room can only summon 1 monster at a time. (only the Summoning option) // Turn it off (0) means the player can summon a lot of monsters as long as the player has enough zeny/item. High rate server players love the room with a lot MVPs // Turn it on (1) means the player have to kill existing monster before can summon a new one. Low rate server player prefer to take out MVP 1 by 1 set .floodcontrol, 1; // if .floodcontrol is turn off, your players might experience lag if they summoned too many MVPs // so what is the maximum input to limit your players summon too many ? set .inputlimit, 30; // If the room has left over monsters while nobody in the room and the room not give up yet, shall we kill monsters in empty room ? set .killmonster, 1; // Default is yes // Options menu setting for MVP Summoner NPC. set .@menu[0], 1; // Turn Heal option On/Off set .@menu[1], 1; // Turn Group 1 summons On/Off -> MVP set .@menu[2], 1; // Turn Group 2 summons On/Off -> mini boss set .@menu[3], 0; // Turn Group 3 summons On/Off set .@menu[4], 0; // Turn Group 4 summons On/Off set .@menu[5], 0; // Turn Group 5 summons On/Off set .@menu[6], 0; // Turn Group 6 summons On/Off set .@menu[7], 0; // Turn Group 7 summons On/Off set .@menu[8], 0; // Turn Group 8 summons On/Off set .@menu[9], 0; // Turn Group 9 summons On/Off set .@menu[10], 0; // Sell shop items options On/Off ( shop npc above ) // set respawn point when they leave the room. Obviously warp to the Private MVP Room Warper npc set .respawnmap$, "prontera"; // Note : "SavePoint" does NOT work set .respawnx, 150; set .respawny, 174; // The minimum GM level can kick a room in use set .gmlvlkick, 80; // .limitspawn in previous revision changed to .grouplimit . // it is for limit each monster spawn per session, prevent them only killing same monster again and again // Now you can configure one group has limited summon, and another group has unlimited summon // Tips: if you server has an insane custom MVP, you can put your custom mob to Group 3~9 with insane item cost, and limit only 1 summon per session // .grouplimit use amount, means if group1limit set to 10, then each session can only summon up to 10 amount of that kind of monster. 0 is unlimited // --------- // Group 1 -> MVP // --------- set .group1name$, "MVP"; // Group 1 name set .group1itemid, 674; // item id use for summon any Group 1 monster - 674 - mithil coin set .group1itemamount, 0; // amount of items to summon a Group 1 monster set .group1cost, 100000; // if no item is specify, zeny cost to summon a Group 1 monster set .group1limit, 0; // limit of summon of Group 1 monster per session, prevent them only killing same monster again and again setarray .group1id, 1511,// Amon Ra 1647,// Assassin Cross Eremes 1785,// Atroce 1630,// Bacsojin 1039,// Baphomet 1874,// Beelzebub 1272,// Dark Lord 1719,// Datale 1046,// Doppelgangger 1389,// Dracula 1112,// Drake 1115,// Eddga 1418,// Evil Snake Lord 1871,// Fallen Bishop 1252,// Garm 1768,// Gloom Under Night 1086,// Golden Thief Bug 1885,// Gopinich 1649,// High Priest Magaleta 1651,// High Wizard Katrinn 1832,// Ifrit 1492,// Incantation Samurai 1734,// Kiel D-01 1251,// Knight of Windstorm 1779,// Ktullanux // 1980,// Kubkin ( I think this mvp is still new ) 1688,// Lady Tanee 1646,// Lord Knight Seyren 1373,// Lord of Death 1147,// Maya 1059,// Mistress 1150,// Moonlight Flower 1087,// Orc Hero 1190,// Orc Lord 1038,// Osiris 1157,// Pharaoh 1159,// Phreeoni 1623,// RSX 0806 1650,// Sniper Shecil 1583,// Tao Gunka 1708,// Thanatos 1312,// Turtle General 1751,// Valkyrie Randgris 1685,// Vesper 1648,// Whitesmith Harword 1917,// Wounded Morroc 1658;// Ygnizem // --------- // Group 2 -> mini boss // --------- set .group2name$, "mini boss"; // Group 2 name set .group2itemid, 674; // item id use for summon any Group 2 monster - 674 - mithil coin set .group2itemamount, 0; // amount of items to summon a Group 2 monster set .group2cost, 10000; // if no item is specify, zeny cost to summon a Group 2 monster set .group2limit, 0; // limit of summon of Group 2 monster per session, prevent them only killing same monster again and again setarray .group2id, 1096,// Angeling 1388,// Archangeling 1795,// Bloody Knight 1830,// Bow Guardian 1839,// Byorgue 1309,// Cat O' Nine Tail 1283,// Chimera 1302,// Dark Illusion 1198,// Dark Priest 1582,// Deviling 1091,// Dragon Fly 1093,// Eclipse 1205,// Executioner 1783,// Galion 1592,// Gangster 1120,// Ghostring 1259,// Gryphon 1720,// Hydro 1090,// Mastering 1289,// Maya Purple 1262,// Mutant Dragon 1203,// Mysteltainn 1870,// Necromancer 1295,// Owl Baron 1829,// Sword Guardian 1204,// Tirfing 1089,// Toad 1092,// Vagabond Wolf 1765;// Valkyrie // --------- // Group 3 // --------- set .group3name$, "Poring-Family"; // Group 3 name set .group3itemid, 12109; // item id use for summon any Group 3 monster - 12109 - Poring box set .group3itemamount, 1; // amount of items to summon a Group 3 monster set .group3cost, 0; // if no item is specify, zeny cost to summon a Group 3 monster set .group3limit, -5; // limit of summon of Group 3 monster per session, prevent them only killing same monster again and again setarray .group3id, 1002,// Poring 1113,// Drops 1031,// Poporing 1242,// Marin 1062,// Santa Poring 1613,// Metaling 1784,// Stapo 1090,// Mastering 1096,// Angeling 1120,// Ghostring 1582,// Deviling 1388,// Arc Angeling 1502;// Pori Pori // --------- // Group 4 // --------- set .group4name$, ""; // Group 4 name set .group4itemid, 0; // item id use for summon any Group 4 monster set .group4itemamount, 0; // amount of items to summon a Group 4 monster set .group4cost, 0; // if no item is specify, zeny cost to summon a Group 4 monster set .group4limit, 0; // limit of summon of Group 4 monster per session, prevent them only killing same monster again and again setarray .group4id, 1001, 1002; // --------- // Group 5 // --------- set .group5name$, ""; // Group 5 name set .group5itemid, 0; // item id use for summon any Group 5 monster set .group5itemamount, 0; // amount of items to summon a Group 5 monster set .group5cost, 0; // if no item is specify, zeny cost to summon a Group 5 monster set .group5limit, 0; // limit of summon of Group 5 monster per session, prevent them only killing same monster again and again setarray .group5id, 1001, 1002; // --------- // Group 6 // --------- set .group6name$, ""; // Group 6 name set .group6itemid, 0; // item id use for summon any Group 6 monster set .group6itemamount, 0; // amount of items to summon a Group 6 monster set .group6cost, 0; // if no item is specify, zeny cost to summon a Group 6 monster set .group6limit, 0; // limit of summon of Group 6 monster per session, prevent them only killing same monster again and again setarray .group6id, 1001, 1002; // --------- // Group 7 // --------- set .group7name$, ""; // Group 7 name set .group7itemid, 0; // item id use for summon any Group 7 monster set .group7itemamount, 0; // amount of items to summon a Group 7 monster set .group7cost, 0; // if no item is specify, zeny cost to summon a Group 7 monster set .group7limit, 0; // limit of summon of Group 7 monster per session, prevent them only killing same monster again and again setarray .group7id, 1001, 1002; // --------- // Group 8 // --------- set .group8name$, ""; // Group 8 name set .group8itemid, 0; // item id use for summon any Group 8 monster set .group8itemamount, 0; // amount of items to summon a Group 8 monster set .group8cost, 0; // if no item is specify, zeny cost to summon a Group 8 monster set .group8limit, 0; // limit of summon of Group 8 monster per session, prevent them only killing same monster again and again setarray .group8id, 1001, 1002; // --------- // Group 9 // --------- set .group9name$, ""; // Group 9 name set .group9itemid, 0; // item id use for summon any Group 9 monster set .group9itemamount, 0; // amount of items to summon a Group 9 monster set .group9cost, 0; // if no item is specify, zeny cost to summon a Group 9 monster set .group9limit, 0; // limit of summon of Group 9 monster per session, prevent them only killing same monster again and again setarray .group9id, 1001, 1002; // Config Ends ------------------------------------------------------------------------ if ( .timeout == 0 ) set .timeout, 60; if ( .nobodygiveup == 0 ) set .nobodygiveup, 5; if ( .inputlimit < 1 ) set .inputlimit, 1; if ( .rentitemid && .rentitemamount ) { if ( getitemname(.rentitemid) == "null" ) { debugmes "Private MVP Room: Rent a room is using invalid item id."; } } set .@i, 1; while ( .@i <= 9 ) { if ( .@menu[.@i] && getd(".group"+ .@i +"itemid") && getd(".group"+ .@i +"itemamount") ) { if ( getitemname( getd(".group"+ .@i +"itemid") ) == "null" ) { debugmes "Private MVP Room: Group no. "+ .@i +" is using invalid item id."; } } set .@i, .@i +1 ; } set .menu$, ( (.@menu[0])?"Heal":"" )+":"+( (.@menu[1])?"Summon "+ .group1name$:"" )+":"+( (.@menu[2])?"Summon "+ .group2name$:"" )+":"+( (.@menu[3])?"Summon "+ .group3name$:"" )+":"+( (.@menu[4])?"Summon "+ .group4name$:"" )+":"+( (.@menu[5])?"Summon "+ .group5name$:"" )+":"+( (.@menu[6])?"Summon "+ .group6name$:"" )+":"+( (.@menu[7])?"Summon "+ .group7name$:"" )+":"+( (.@menu[8])?"Summon "+ .group8name$:"" )+":"+( (.@menu[9])?"Summon "+ .group9name$:"" )+":"+( (.@menu[10])?"Buy branches":"" )+":Leave this room:Give up this room"; set .@i, 1; while ( .@i <= 9 ) { setd ".group"+ .@i +"idsize", getarraysize( getd(".group"+ .@i +"id") ); if ( .@menu[.@i] && getd(".group"+ .@i +"limit") <= 0 ) { set .@j, 0; while ( .@j < getd(".group"+ .@i +"idsize") ) { setd ".group"+ .@i +"menu$", getd(".group"+ .@i +"menu$") + getmonsterinfo( getd(".group"+ .@i +"id["+ .@j +"]"), 0) +":"; set .@j, .@j +1 ; } } set .@i, .@i +1 ; } } else { sleep 1; mapannounce .@map$, "Admin has refresh the server, please register the room again.", 1; mapwarp .@map$, .respawnmap$, .respawnx, .respawny; } end; L_Start: // I hate gotos ... but ... set .@dif, strnpcinfo(2); if ( .remind[.@dif] == 0 ) { set .remind[.@dif], 1; initnpctimer; } mes "[MVP Summoner]"; mes "Hi, what can I do for you ?"; next; switch ( select(.menu$) ) { case 1: mes "[MVP Summoner]"; if ( mobcount("this","") > 0 ) { mes "I cannot offer heal service when there are monsters around."; close; } sc_end sc_stone; sc_end sc_slowdown; sc_end sc_freeze; sc_end sc_sleep; sc_end sc_curse; sc_end sc_silence; sc_end sc_confusion; sc_end sc_blind; sc_end sc_bleeding; sc_end sc_decreaseagi; sc_end sc_poison; sc_end sc_hallucination; sc_end sc_stripweapon; sc_end sc_striparmor; sc_end sc_striphelm; sc_end sc_stripshield; sc_end sc_changeundead; sc_end sc_orcish; sc_end sc_berserk; sc_end sc_ske; sc_end sc_swoo; sc_end sc_ska; percentheal 100,100; specialeffect2 7; mes "You have completely healed."; close; default: set .@group, @menu -1; if ( .floodcontrol && mobcount("this","") > 0 ) { mes "[MVP Summoner]"; mes "I cannot summon another monster when there are monsters around."; close; } else if ( getd(".group"+ .@group +"itemid") && getd(".group"+ .@group +"itemamount") ) { mes "[MVP Summoner]"; mes "The cost to summon a "+ getd(".group"+ .@group +"name$") +" is "+ getd(".group"+ .@group +"itemamount") +" "+ getitemname( getd(".group"+ .@group +"itemid") ) +"."; if ( getd(".group"+ .@group +"limit") < 0 ) mes "("+( ( ~getd(".group"+ .@group +"limit")+1 - getd(".group"+ .@group +"limit"+ .@dif) <= 0 )?0:( ~getd(".group"+ .@group +"limit")+1 - getd(".group"+ .@group +"limit"+ .@dif) ) )+") more summons for this group."; next; } else if ( getd(".group"+ .@group +"cost") ) { mes "[MVP Summoner]"; mes "The cost to summon a "+ getd(".group"+ .@group +"name$") +" is "+ callfunc("int__", getd(".group"+ .@group +"cost") ) +" zeny."; if ( getd(".group"+ .@group +"limit") < 0 ) mes "("+( ( ~getd(".group"+ .@group +"limit")+1 - getd(".group"+ .@group +"limit"+ .@dif) <= 0 )?0:( ~getd(".group"+ .@group +"limit")+1 - getd(".group"+ .@group +"limit"+ .@dif) ) )+") more summons for this group."; next; } else if ( getd(".group"+ .@group +"limit") < 0 ) { mes "[MVP Summoner]"; mes "("+( ( ~getd(".group"+ .@group +"limit")+1 - getd(".group"+ .@group +"limit"+ .@dif) <= 0 )?0:( ~getd(".group"+ .@group +"limit")+1 - getd(".group"+ .@group +"limit"+ .@dif) ) )+") more summons for this group."; next; } if ( getd(".group"+ .@group +"limit") < 0 && getd(".group"+ .@group +"limit"+ .@dif) >= ~getd(".group"+ .@group +"limit")+1 ) { mes "[MVP Summoner]"; mes "I'm sorry, but you can't summon any more monster for this group."; close; } else if ( getd(".group"+ .@group +"limit") > 0 ) { for ( set .@i, 0; .@i < getd(".group"+ .@group +"idsize"); set .@i, .@i +1 ) set .@menu$, .@menu$ +( ( getd(".group"+ .@group +"limit"+ .@dif +"["+ .@i +"]") >= getd(".group"+ .@group +"limit") )?"^999999":"^000000" )+ getmonsterinfo( getd(".group"+ .@group +"id["+ .@i +"]"), 0) +" ("+ ( ( getd(".group"+ .@group +"limit") - getd(".group"+ .@group +"limit"+ .@dif +"["+ .@i +"]") <= 0 )?0:( getd(".group"+ .@group +"limit") - getd(".group"+ .@group +"limit"+ .@dif +"["+ .@i +"]") ) ) +")"+":"; set .@menu, select(.@menu$) -1; } else set .@menu, select( getd(".group"+ .@group +"menu$") ) -1; mes "[MVP Summoner]"; if ( .floodcontrol == 0 && .inputlimit > 1 ) { mes "Input an amount of monsters to summon."; next; input .@amount; if ( .@amount == 0 ) close; else if ( .@amount > .inputlimit ) set .@amount, .inputlimit; mes "[MVP Summoner]"; } else set .@amount, 1; if ( getd(".group"+ .@group +"itemid") && getd(".group"+ .@group +"itemamount") ) { if ( countitem( getd(".group"+ .@group +"itemid") ) < getd(".group"+ .@group +"itemamount") * .@amount ) { mes "You don't have enough "+ getitemname( getd(".group"+ .@group +"itemid") ) +" to summon a "+ getd(".group"+ .@group +"name$") +"."; close; } } else if ( getd(".group"+ .@group +"cost") ) { if ( zeny < getd(".group"+ .@group +"cost") * .@amount ) { mes "You don't have enough zeny to summon a "+ getd(".group"+ .@group +"name$") +"."; close; } } if ( .floodcontrol && mobcount("this","") > 0 ) { mes "I cannot summon another monster when there are monsters around."; close; } else if ( getd(".group"+ .@group +"limit") > 0 ) { if ( getd(".group"+ .@group +"limit"+ .@dif +"["+ .@menu +"]") >= getd(".group"+ .@group +"limit") ) { mes "I'm sorry, but you already summoned that monster too much. Try summon another."; close; } else if ( getd(".group"+ .@group +"limit"+ .@dif +"["+ .@menu +"]") + .@amount > getd(".group"+ .@group +"limit") ) { mes "The amount you input is more than the limit you can summon. Try reduce the amount."; close; } } else if ( getd(".group"+ .@group +"limit") < 0 ) { if ( getd(".group"+ .@group +"limit"+ .@dif) >= ~getd(".group"+ .@group +"limit")+1 ) { mes "I'm sorry, but you can't summon any more monster for this group."; close; } else if ( getd(".group"+ .@group +"limit"+ .@dif) + .@amount > ~getd(".group"+ .@group +"limit")+1 ) { mes "The amount you input is more than the limit you can summon. Try reduce the amount."; close; } } mes "Summoning "+ .@amount +" "+ getmonsterinfo( getd(".group"+ .@group +"id["+ .@menu +"]"), 0) +"."; mes "Ok, get ready ?"; close2; if ( .floodcontrol && mobcount("this","") > 0 ) end; if ( getd(".group"+ .@group +"itemid") && getd(".group"+ .@group +"itemamount") ) { if ( countitem( getd(".group"+ .@group +"itemid") ) < getd(".group"+ .@group +"itemamount") * .@amount ) end; delitem getd(".group"+ .@group +"itemid"), getd(".group"+ .@group +"itemamount") * .@amount; } else if ( getd(".group"+ .@group +"cost") ) { if ( zeny < getd(".group"+ .@group +"cost") * .@amount ) end; set zeny, zeny - getd(".group"+ .@group +"cost") * .@amount; } if ( getd(".group"+ .@group +"limit") > 0 ) { if ( getd(".group"+ .@group +"limit"+ .@dif +"["+ .@menu +"]") + .@amount > getd(".group"+ .@group +"limit") ) end; setd ".group"+ .@group +"limit"+ .@dif +"["+ .@menu +"]", getd(".group"+ .@group +"limit"+ .@dif +"["+ .@menu +"]") + .@amount; } else if ( getd(".group"+ .@group +"limit") < 0 ) { if ( getd(".group"+ .@group +"limit"+ .@dif) + .@amount > ~getd(".group"+ .@group +"limit")+1 ) end; setd ".group"+ .@group +"limit"+ .@dif, getd(".group"+ .@group +"limit"+ .@dif) + .@amount; } monster "this", 0, 0, "--ja--", getd(".group"+ .@group +"id["+ .@menu +"]"), .@amount; end; case 11: if ( mobcount("this","") > 0 ) { mes "[MVP Summoner]"; mes "I cannot offer this service when there are monsters around."; close; } close2; callshop "MVP room#branch", 0; end; case 12: mes "[MVP Summoner]"; mes "Are you sure you want to leave this room ?"; mes "If this room left empty for more than "+ .nobodygiveup +" minutes, you lost ownership for this room."; if ( select( "Yes:No") == 2 ) close; warp .respawnmap$, .respawnx, .respawny; end; case 13: mes "[MVP Summoner]"; getmapxy .@map$, .@x, .@y, 0; if ( getmapusers(.@map$) > 1 ) { mes "There are still some players in this room. Make sure you are the last member in this room to use this option."; close; } mes "Are you sure you want to give up this room ?"; if ( .rentcost ) mes "You will need to pay again to enter this room."; next; if ( select( "Yes:No" ) == 2 ) close; warp .respawnmap$, .respawnx, .respawny; set .remaintime[.@dif], -1; end; } close; OnEnterMap: set .@dif, strnpcinfo(2); set .remind[.@dif], 0; for ( set .@i, 1; .@i <= 9; set .@i, .@i +1 ) deletearray getd(".group"+ .@i +"limit"+ .@dif), getd(".group"+ .@i +"idsize"); set .nobodycounter[.@dif], 0; getmapxy .@map$, .@x, .@y ,1; set .starttime[.@dif], gettimetick(2); do { set .remaintime[.@dif], .timeout * 60 + .starttime[.@dif] - gettimetick(2); set .@hour[.@dif], .remainTime[.@dif] / 3600 ; set .@min[.@dif], .remainTime[.@dif] % 3600 / 60 ; set .@sec[.@dif], .remainTime[.@dif] % 3600 % 60 ; delwaitingroom strnpcinfo(0); waitingroom "Time Left = "+( ( .@hour[.@dif] )?( .@hour[.@dif] +":"):"" )+( ( .@min[.@dif] < 10 )?"0"+ .@min[.@dif]: .@min[.@dif] )+":"+( ( .@sec[.@dif] < 10 )?"0"+ .@sec[.@dif]: .@sec[.@dif] ), 0; if ( getmapusers(.@map$) ) set .nobodycounter[.@dif], 0; else { set .nobodycounter[.@dif], .nobodycounter[.@dif] +1 ; if ( .nobodycounter[.@dif] > .nobodygiveup * 60 ) break; } sleep 995; } while ( .remaintime[.@dif] > 1 ); set .remaintime[.@dif], 0; delwaitingroom "MVP Summoner#"+ .@dif; mapwarp .@map$, .respawnmap$, .respawnx, .respawny; end; OnTimer100: stopnpctimer; npctalk "Hi ~ the bubble above my head is the countdown for using this room."; sleep 2000; npctalk "Sometimes, I can skip for about 1 second in the countdown."; sleep 3000; npctalk "That is because the server is experiencing minor lag problem."; sleep 3000; npctalk "So, don't complain about me cheated for the countdown ~ ^.^"; sleep 3000; npctalk "Have a nice day ~"; end; } prontera,148,174,5 script Private MVP Room 100,{ mes "[Private MVP Room]"; mes "Please select a private MVP room."; if ( getvariableofnpc(.rentitemid, "MVP Summoner") && getvariableofnpc(.rentitemamount, "MVP Summoner") ) mes "The cost to rent a room for "+ getvariableofnpc(.timeout, "MVP Summoner") +" minutes is "+ getvariableofnpc(.rentitemamount, "MVP Summoner") +" "+ getitemname( getvariableofnpc(.rentitemid, "MVP Summoner") ) +"."; else if ( getvariableofnpc(.rentcost, "MVP Summoner") ) mes "The cost to rent a room for "+ getvariableofnpc(.timeout, "MVP Summoner") +" minutes is "+ callfunc("int__", getvariableofnpc(.rentcost, "MVP Summoner") ) +" zeny."; else mes "You can only use the room for only "+ getvariableofnpc(.timeout, "MVP Summoner") +" minutes."; mes " "; for ( set .@i, 1; .@i <= 8; set .@i, .@i +1 ) { if ( getvariableofnpc(.remaintime[.@i],"MVP Summoner") ) { switch ( .type[.@i] ) { case 1: set .@color$, "^EE8800"; break; case 2: set .@color$, "^70CC11"; break; case 3: set .@color$, "^0000FF"; break; default: set .@color$, "^000000"; } mes "Room #"+ .@i +" = "+ .@color$ + .whoinuse$[.@i] +"^000000"; } } next; set .@room, select("MVP Room 1 ["+ getmapusers("06guild_01") +"]", "MVP Room 2 ["+ getmapusers("06guild_02") +"]", "MVP Room 3 ["+ getmapusers("06guild_03") +"]", "MVP Room 4 ["+ getmapusers("06guild_04") +"]", "MVP Room 5 ["+ getmapusers("06guild_05") +"]", "MVP Room 6 ["+ getmapusers("06guild_06") +"]", "MVP Room 7 ["+ getmapusers("06guild_07") +"]", "MVP Room 8 ["+ getmapusers("06guild_08") +"]"); if ( getvariableofnpc(.remaintime[.@room],"MVP Summoner") ) { if ( .inuseid[.@room] == getcharid(.type[.@room]) ) { if ( getvariableofnpc(.killmonster,"MVP Summoner") && getmapusers("06guild_0"+ .@room) == 0 ) killmonsterall "06guild_0"+ .@room; warp "06guild_0"+ .@room, 0,0; end; } else { mes "[Private MVP Room]"; switch ( .type[.@room] ) { case 1: set .@color$, "^EE8800Party "; break; case 2: set .@color$, "^70CC11Guild "; break; case 3: set .@color$, "^0000FFPlayer "; } mes "This room is reserved for "; mes .@color$ + .whoinuse$[.@room] +"^000000 ."; if ( getgmlevel() < getvariableofnpc(.gmlvlkick,"MVP Summoner") ) { mes "Please select another."; close; } mes " "; mes "Currently there are "+ getmapusers("06guild_0"+ .@room) +" players"; mes "in that room."; set .@remaintime, getvariableofnpc(.remaintime[.@room],"MVP Summoner"); mes "It still has "+( .@remaintime /60 )+"mn "+( .@remaintime %60 )+"s left."; set .@nobodycounter, getvariableofnpc(.nobodycounter[.@room],"MVP Summoner"); if ( .@nobodycounter ) mes "And have left empty for "+( .@nobodycounter /60 )+"mn "+( .@nobodycounter %60 )+"s."; mes "Kick them ?"; next; if ( select ( "No:Yes" ) == 1 ) close; set getvariableofnpc(.remaintime[.@room],"MVP Summoner"), -1; mes "[Private MVP Room]"; mes "Room#"+ .@room +" is empty now."; close; } } mes "[Private MVP Room]"; if ( getvariableofnpc(.rentitemid, "MVP Summoner") && getvariableofnpc(.rentitemamount, "MVP Summoner") ) { if ( countitem(getvariableofnpc(.rentitemid, "MVP Summoner")) < getvariableofnpc(.rentitemamount, "MVP Summoner") ) { mes "You don't have enough "+ getitemname( getvariableofnpc(.rentitemid, "MVP Summoner") ) +" to rent a room."; close; } } else if ( getvariableofnpc(.rentcost, "MVP Summoner") ) { if ( zeny < getvariableofnpc(.rentcost, "MVP Summoner") ) { mes "You don't have enough zeny to rent a room."; close; } } mes "You reserve this room for ..."; next; set .@type, select("For my party members", "For my guild members", "For personal account use" ); if ( getcharid(.@type) == 0 ) { mes "[Private MVP Room]"; mes "You do not own a "+( (.@type == 1)?"Party":"Guild" )+"."; close; } else if ( getvariableofnpc(.rentitemid, "MVP Summoner") && getvariableofnpc(.rentitemamount, "MVP Summoner") ) { if ( countitem(getvariableofnpc(.rentitemid, "MVP Summoner")) < getvariableofnpc(.rentitemamount, "MVP Summoner") ) { mes "You don't have enough "+ getitemname( getvariableofnpc(.rentitemid, "MVP Summoner") ) +" to rent a room."; close; } } else if ( getvariableofnpc(.remaintime[.@room],"MVP Summoner") ) { mes "[Private MVP Room]"; mes "I'm sorry, somebody else has already register this room faster than you."; close; } for ( set .@i, 1; .@i <= 8; set .@i, .@i +1 ) { if ( getvariableofnpc(.remaintime[.@i],"MVP Summoner") && .@type == .type[.@i] && getcharid(.@type) == .inuseid[.@i] ) { mes "[Private MVP Room]"; mes "You already rented Room#"+ .@i +". Use that room instead."; close; } } set .type[.@room], .@type; set .inuseid[.@room], getcharid(.@type); set .whoinuse$[.@room], strcharinfo( (.@type == 3)?0:.@type ); if ( getvariableofnpc(.rentitemid, "MVP Summoner") && getvariableofnpc(.rentitemamount, "MVP Summoner") ) { if ( countitem(getvariableofnpc(.rentitemid, "MVP Summoner")) < getvariableofnpc(.rentitemamount, "MVP Summoner") ) end; delitem getvariableofnpc(.rentitemid, "MVP Summoner"), getvariableofnpc(.rentitemamount, "MVP Summoner"); } else if ( getvariableofnpc(.rentcost, "MVP Summoner") ) { if ( zeny < getvariableofnpc(.rentcost, "MVP Summoner") ) end; set zeny, zeny - getvariableofnpc(.rentcost, "MVP Summoner"); } warp "06guild_0"+ .@room, 0,0; killmonsterall "06guild_0"+ .@room; donpcevent "MVP Summoner#"+ .@room +"::OnEnterMap"; end; } 06guild_01,49,49,4 duplicate(MVP Summoner) MVP Summoner#1 116 06guild_02,49,49,4 duplicate(MVP Summoner) MVP Summoner#2 116 06guild_03,49,49,4 duplicate(MVP Summoner) MVP Summoner#3 116 06guild_04,49,49,4 duplicate(MVP Summoner) MVP Summoner#4 116 06guild_05,49,49,4 duplicate(MVP Summoner) MVP Summoner#5 116 06guild_06,49,49,4 duplicate(MVP Summoner) MVP Summoner#6 116 06guild_07,49,49,4 duplicate(MVP Summoner) MVP Summoner#7 116 06guild_08,49,49,4 duplicate(MVP Summoner) MVP Summoner#8 116 06guild_01 mapflag nowarpto 06guild_02 mapflag nowarpto 06guild_03 mapflag nowarpto 06guild_04 mapflag nowarpto 06guild_05 mapflag nowarpto 06guild_06 mapflag nowarpto 06guild_07 mapflag nowarpto 06guild_08 mapflag nowarpto 06guild_01 mapflag nomemo 06guild_02 mapflag nomemo 06guild_03 mapflag nomemo 06guild_04 mapflag nomemo 06guild_05 mapflag nomemo 06guild_06 mapflag nomemo 06guild_07 mapflag nomemo 06guild_08 mapflag nomemo 06guild_01 mapflag noteleport 06guild_02 mapflag noteleport 06guild_03 mapflag noteleport 06guild_04 mapflag noteleport 06guild_05 mapflag noteleport 06guild_06 mapflag noteleport 06guild_07 mapflag noteleport 06guild_08 mapflag noteleport 06guild_01 mapflag nosave SavePoint 06guild_02 mapflag nosave SavePoint 06guild_03 mapflag nosave SavePoint 06guild_04 mapflag nosave SavePoint 06guild_05 mapflag nosave SavePoint 06guild_06 mapflag nosave SavePoint 06guild_07 mapflag nosave SavePoint 06guild_08 mapflag nosave SavePoint 06guild_01 mapflag nopenalty 06guild_02 mapflag nopenalty 06guild_03 mapflag nopenalty 06guild_04 mapflag nopenalty 06guild_05 mapflag nopenalty 06guild_06 mapflag nopenalty 06guild_07 mapflag nopenalty 06guild_08 mapflag nopenalty got this errors anyone can help Thank you!
  4. [ Creating an Open-source Ragnarok Online Server with kRO & OpenKore Support ] [ Table Of Contents ] Introduction Master List: All The Required Downloads Microsoft Visual Studio 2022: Installation Laragon: Installing and Upgrading rAthena: Installing, Configuring, and Optimizing Flux Control Panel: Installing and Modifying The kRO Client: Updating, Diffing, Hexing, Translating, and Customizing The OpenKore Client: Packet Extraction, Configuration, and Field Updating Logging Into Your Server, Making a GM Account, and Playing! Troubleshooting The Situation Packaging It Up For Transportation Post Install House Cleaning Conclusion [ Introduction ]I'd like to walk you through the complete process of creating an up-to-date open-source server for Ragnarok Online using rAthena. This includes removing all of its security so that it can be accessed via multiple clients. Next, we'll install a web management control panel that users can create accounts on, submit tickets with, even research your servers’ unique stats and databases. Afterwards we're going to transform the latest official Korean client by diffing, hexing, translating, & heavily customizing it. Finally, we're going to configure the OpenKore client to work with our server. As well support interfacing with the official client through proxy.We're going to be using the same packet structure across all aspects so that they can properly communicate with each other. This was selected by researching what the last fully developed version was for OpenKore. (2020-04-01b) Since this is running primarily open-source software, it slowly gets better overtime. This is actually ahead of the International Servers and many other countries not only in features but content. I've included the full process so that anyone can take the next or a different set of packets and reproduce these results. This is also completely portable. Ends with one folder, drag and drop. All software included is free, there is zero piracy endorsed. [ Master List: All The Required Downloads ] [ 3.8GB ]Compiling and Editing:01.) Microsoft Visual Studio (link)02.) Notepad++ (link)Databases and Webserver:03.) Laragon Portable (link)04.) MariaDB Server 10.7.3 (link)05.) PHP 7.4.28 (non thread safe) (link)06.) Nginx 1.21.6 Mainline (link)07.) HeidiSQL 11.3 (64 portable) (link)Server Emulator and Web Management:08.) rAthena (link)09.) Flux Control Panel: (link)Official Client:10.) kRO (v20210406) (link)11.) 2020-04-01bRagexe (link)12.) ROenglishRE (link)13.) RO Patcher Lite (link)14.) RO OpenSetup (link)15.) Nemo (link)OpenKore Client:16.) OpenKore (link)17.) Winsock Packet Editor (link) (password: openkore)Troubleshooting:18.) Visual C++ Redistributable Runtimes All-in-One (link)[ Microsoft Visual Studio 2022: Installation ] [ 7.62GB ]01.) Execute "VisualStudioSetup.exe". (let it update)02.) At the install screen, scroll down to the "Desktop & Mobile" section.03.) Checkmark "Desktop development with C++".04.) Then look on the right side under "Installation details", go to the "Optional" section.05.) Uncheck "Just-In-Time debugger". (this will remove Live Share as well)06.) Uncheck "C++ profiling tools".07.) Uncheck "C++ CMake tools for Windows".08.) Uncheck "C++ ATL for latest v143 build tools (x86 x64)".09.) Uncheck "Test Adapter for Boost.Test".10.) Uncheck "Test Adapter for Google Test".11.) Uncheck "IntelliCode".12.) Uncheck "C++ AddressSanitizer".13.) Click Install. (in bottom right)Note: Wow! Even stripped down, this is a massive 7.62GB installation. Depending on how you access the internet this might take a while. Also, consider how far into the future you are from the time of this post. The install size will be different given it's continually updated. Feel free to move on while this is running in the background. You won't actually need to compile anything until you reach Step 14 of the rAthena section.14.) Install Notepad++ (execute npp.8.3.2.Installer.x64)Note: Moving forward, I highly suggest using Notepad++ to create and edit files. Primarily so you can get a line count without needing to boot all of Visual Studio. This is a clean and lightweight solution.[ Laragon: Installing and Upgrading ]01.) Extract Laragon Portable.02.) Delete "php-5.4.9-nts-Win32-VC9-x86" from "\laragon\bin\php".03.) Extract "php-7.4.28-nts-Win32-vc15-x64" as a folder into "\laragon\bin\php".04.) Delete "mysql-5.1.72-win32" from "\laragon\bin\mysql".05.) Extract "mariadb-10.7.3-winx64" as a folder into "\laragon\bin\mysql".06.) Delete "nginx-1.14.0" from "\laragon\bin\nginx".07.) Extract "nginx-1.21.6" as a folder into "\laragon\bin\nginx".08.) Delete all the contents of "\laragon\bin\heidisql".09.) Extract "HeidiSQL_11.3_64_Portable" directly into "\laragon\bin\heidisql".10.) Open Laragon. Click Start All.11.) Grant MariaDB and Nginx firewall permissions when prompted.12.) Close Laragon window, do not exit the program. Don't worry it's still running in your system tray.[ rAthena: Installing, Configuring, and Optimizing ]01.) Extract rAthena.02.) Go to "\rathena\conf". Rename the "import-tmpl" folder to "import".03.) Open: "\rathena\conf\import\char_conf.txt", add: // Server Communication username and password. userid: supercool passwd: coolsuper server_name: GoblinRO // Login Server IP // The character server connects to the login server using this IP address. // NOTE: This is useful when you are running behind a firewall or are on // a machine with multiple interfaces. login_ip: 127.0.0.1 // Character Server IP // The IP address which clients will use to connect. // Set this to what your server's public IP address is. char_ip: 192.168.1.130 // Starting point for new characters. start_point: iz_int,18,26 // Amount of time in seconds by which the character deletion is delayed. char_del_delay: 10 // Restrict character deletion by email address or birthdate. char_del_option: 1 // Restrict character deletion as long as he is still in a party or guild. char_del_restriction: 0 // Pincode system pincode_enabled: no Note: You're going to want to enter your own userid/passwd, server name, and server IP. (wan if going off network)04.) Open: "\rathena\conf\import\inter_conf.txt", add: "use_sql_db: yes"05.) Open: "\rathena\conf\import\log_conf.txt", add: // log_filter: 1 = logs ANY items log_filter: 1 // log_chat: 63 = logs everything log_chat: 63 06.) Open: "\rathena\conf\import\login_conf.txt", add: // Can you use _M/_F to make new accounts on the server? // Note: This only works if client side password encryption is not enabled. new_account: yes // Ipban features ipban_enable: no 07.) Open: "\rathena\conf\import\map_conf.txt", add: // Server Communication username and password. userid: supercool passwd: coolsuper // Character Server IP // The map server connects to the character server using this IP address. // NOTE: This is useful when you are running behind a firewall or are on // a machine with multiple interfaces. char_ip: 127.0.0.1 // Map Server IP // The IP address which clients will use to connect. // Set this to what your server's public IP address is. map_ip: 192.168.1.130 Note: You're going to want to enter the same userid/passwd and IP used in char_conf.txt.08.) Open: "\rathena\conf\import\packet_conf.txt", add: // IP rules // allow : Accepts connections from the ip range (even if flagged as DDoS) allow: 127.0.0.1 allow: 192.168.0.0/16 Note: Change to match your network setup.09.) Open: "\rathena\src\config\packets.hpp". Comment out lines: 44-62. (packet obfuscation)10.) Open: "\rathena\src\custom\defines_pre.hpp". Line 12 add: "#define PACKETVER 20200401".11.) Open: "\rathena\npc\re\warps\cities\izlude.txt". Comment out lines: 39-54.12.) Open: "\rathena\npc\re\warps\fields\prontera_fild.txt". Comment out lines: 94-113.Note: Why are removing these warps important? So these are the novice start areas to the game. Like any MMORPG these were the most populated maps 24/7/365. It got to the point where they became overflooded not just by new players but bots. You'd wonder around trying to find something to kill that wasn't already taken, to the point leveling actually became a nightmare. So what they did was implement multiple instances of the same maps. Putting players in different load balanced instances allowed everybody to breath and comfortably start the game with some people but not to many.Though this had some downsides. Let's say you just started new characters so you could play with your friends. You might be loaded into prt_fild08a while your friends were loaded into b and c. Meaning there is zero crossover, you're all in your own unique world. You can't see each other, the monsters spawn differently, and that fun starting the game together experience is gone. Given we're setting up a small server here, there is no point in having multiple instances. So we're removing the extras and specifying a singular starting area.13.) Create a new "compile.bat" file inside "\rathena" that contains: @echo off "C:\Program Files\Microsoft Visual Studio\2022\Community\Msbuild\Current\Bin\MSBuild.exe" -m pause Note: Your install location might be different. Adjust accordingly.14.) Execute compile.bat. Wait for it to finish. Check to make sure it's error free at the end.15.) Convert all data files to SQL so you can use MariaDB via running "\rathena\yaml2sql.bat". (you will have to confirm with "Y" ten times during this process)16.) Open "\rathena\sql-files", delete the following: item_db.sql item_db_equip.sql item_db_etc.sql item_db_usable.sql item_db2.sql mob_db.sql mob_db2.sql mob_skill_db.sql mob_skill_db2.sql readme.md 17.) Open "\rathena\sql-files\compatibility" and move "item_db_re_compat.sql" and "item_db2_re_compat.sql" up one level to "\rathena\sql-files". You should now have 16 files (not including folders) inside "\rathena\sql-files".18.) Open Laragon. Click Database. Click New. (bottom left)19.) Under "Session Name", change "Unnamed" to "Laragon". Then click "Open".20.) Click "manage user authentication and privileges" in the top bar.21.) Click "Add". Change username to "ragnarok". Change password to "ragnarok". Checkmark the "Global Privileges" box. Click Save. Click Close.22.) Right click "Laragon" in the top of the left column. Expand "Create new". Click "Database". Enter name "ragnarok". Click OK.23.) Click "ragnarok" in the left column. Go to "File" in the top left. Expand and click "Run SQL File". Direct to "\rathena\sql-files\". Select all 16 .sql files. Click Open. Confirm auto-detect. (let finish)24.) Click "refresh" in the top bar. (next to manage user authentication and privileges)25.) Expand the "ragnarok" database in the left column. Click "login" which will bring it up on the right. Click the "data" tab.26.) Change the account's userid and user_pass to match the server communication username and password created back in step 3.27.) Close these windows. Get back to having Laragon running in your system tray.28.) Open "kRO_FullClient_20210406.zip", extract "msvcr110.dll" into "\rathena".29.) Go to "\rathena", execute "runserver.bat". Three consoles: the login, character, and map servers are going to open.30.) As each part comes online you'll need to grant it firewall access.Note: We're spinning up the server to make sure we're good before moving on. You should see all green status updates.Note: If you plan on including WAN clients, then you'll need to open the: 5121, 6121, 6900, & 80 ports on your network firewall / router. Please consider this a large security risk! The scope of this document does not include properly securing an exposed server. Proceed with caution.[ Flux Control Panel: Installing and Modifying ]01.) Extract FluxCP into "\laragon\www" make sure it's the actual root contents and not just the folder that contains them. (replace index.php)02.) Open "\laragon\www\config\application.php".03.) Line 6: delete BaseURI. EX: 'fluxcp', becomes '',04.) Line 7: change your Installer Password. EX: "secretpassword" becomes "supersecretpassword".05.) Line 43: change MinPasswordLength to 6.06.) Line 45: change PasswordMinUpper to 0.07.) Line 46: change PasswordMinLower to 0.08.) Line 47: change PasswordMinNumber to 0.09.) Line 49: change GMMinPasswordLength to 6.10.) Line 50: change GMPasswordMinUpper to 0.11.) Line 51: change GMPasswordMinLower to 0.12.) Line 52: change GMPasswordMinNumber to 0.13.) Line 53: change GMPasswordMinSymbol to 0.14.) Line 54: change RandomPasswordLength to 6.15.) Line 60: change PincodeEnabled to false.16.) Line 78: change ShowCopyright to false.17.) Line 82: change UseCaptcha to false.18.) Line 99: change AcceptDonations to false.19.) Line 220: change CMSNewsType to 2. (this adds rAthena news) (not required)20.) Line 225: change CMSNewsLimit to 2. (two articles fits the new layout well)21.) Line 233: change SDEnableCreditRewards to false.22.) Comment out lines 251 - 260. (removes fluff from web navigation)23.) Comment out lines 269 - 272. (removes donations from web navigation)24.) Comment out lines 288 - 291. (removes social media from web navigation)25.) Comment out line 305. (removes send email button)26.) Comment out line 307. (removes cash shop button)27.) Comment out lines 329-331. (removes transfer credits and cart)28.) Comment out line 348. (removes cash points)29.) Comment out line 360. (removes paypal)30.) Comment out lines 376 - 380. (removes donations)31.) Save and close file.32.) Open Laragon. Click Database. Click "Open" in the new window. Click "manage user authentication and privileges" in the top bar.33.) Click "Add". Change username to "fluxcpuser". Change password to "fluxcppass". Checkmark the "Global Privileges" box. Click Save. Click Close. Close database window.34.) Open "\laragon\www\config\servers.php".35.) Line 7: change your Server Name to something friendly. EX: "FluxRO" becomes "GoblinRO".36.) Line 17: change your Username from "ragnarok" to "fluxcpuser".37.) Line 18: change your Password from "ragnarok" to "fluxcppass".38.) Line 38: change your Username from "ragnarok" to "fluxcpuser".39.) Line 39: change your Password from "ragnarok" to "fluxcppass".40.) Line 55: change your Server Name to the new one from Line 7.41.) Save and close file.42.) Open Laragon. Click Menu. Expand PHP. Expand Extensions. Click tidy.43.) Click Menu. Expand Nginx. Expand sites-enabled. Click 00-default.conf.44.) Line 9: change "127.0.0.1;" to "all;". Save file. Close file.45.) Open Laragon. Click "Reload" on the Nginx line next to the open port (80).46.) Click Web. The installer should now pop-up in your browser.47.) Enter your installer password changed in Step 4. Click Authenticate.48.) Click "Install or Update Everything". (it's in bold) Confirm process.49.) Once the new site pops up, change the URL from localhost to the IP address of the machine hosting the server. Press enter.50.) Confirm it works and bookmark this page as it's your new control panel, ticket system, and server information tool. (you can click around for fun if you like)Note: You can login via any account on the server or make a new one! During account creation a working email address is NOT required but input of one is. ([email protected], etc.) Accounts flagged as GM in the database will have Admin access in the control panel.[ The kRO Client: Updating, Diffing, Hexing, Translating, and Customizing ]01.) Extract kRO_FullClient_20210406.02.) Extract RO Patcher Lite into "\client".03.) Execute "rsu-kro-rag-lite-x64.exe" and wait for it to finish updating the client.04.) Extract RO OpenSetup into "\client".05.) Extract ROenglishRE.06.) Open "ROenglishRE\Renewal". Copy everything into "\client". (override already present files)07.) Open "ROenglishRE\Client Support\Renewal\2020-09". Copy "data" folder into "\client". (override as well)08.) Extract Nemo. Execute "NEMO.exe".09.) Look for "Input Exe File" at the bottom. Click "Browse". Direct towards "2020-04-01bRagexe.exe".10.) Look for "Output Patched" at the bottom. Click "Browse". Direct towards "\client\2020-04-01bRagexe_patched.exe".11.) Create a new "profile.log" file (any location) that contains: 3 Chat Flood Remove Limit 9 Disable 1rag1 type parameters (Recommended) 14 Disable Hallucination Wavy Screen (Recommended) 16 Disable Swear Filter 20 Extend Chat Box 21 Extend Chat Room Box 22 Extend PM Box 23 Enable /who command (Recommended) 24 Fix Camera Angles (Recommended) 32 Increase Zoom Out Max 34 Enable /showname (Recommended) 35 Read Data Folder First 36 Read msgstringtable.txt (Recommended) 38 Remove Gravity Ads (Recommended) 39 Remove Gravity Logo (Recommended) 41 Disable Nagle Algorithm (Recommended) 44 Translate Client (Recommended) 46 Use Normal Guild Brackets (Recommended) 47 Use Ragnarok Icon 48 Use Plain Text Descriptions (Recommended) 49 Enable Multiple GRFs (Recommended) 50 Skip License Screen 53 Use Ascii on All LangTypes (Recommended) 64 @ Bug Fix (Recommended) 65 Load Custom lua file instead of iteminfo*.lub (Recommended) 73 Remove Hourly Announce (Recommended) 74 Increase Screenshot Quality 84 Remove Serial Display (Recommended) 88 Allow space in guild name 90 Enable DNS Support (Recommended) 91 Disconnect to Login Window 213 Disable Help Message on Login (Recommended) 215 Increase Map Quality 216 Hide Cash Shop 226 Disable Walk To Delay. 230 Always load Korea ExternalSettings lua file (Recommended) 231 Remove hardcoded address/port (Recommended) 232 Restore old login packet (Recommended) 233 Hide SNS Button 242 Disable kRO Site Launch 244 Disable Cheat Defender Game Guard (Recommended) 248 Remove wrong chars from cash shop 253 Skip some hidden menu icon buttons 270 Change AchievementList*.lub path 272 Change Towninfo*.lub path 273 Change PetEvolutionCln*.lub path 274 Change Tipbox*.lub path 275 Change CheckAttendance*.lub path 276 Change OngoingQuestInfoList*.lub path 277 Change RecommendedQuestInfoList*.lub path 278 Change PrivateAirplane*.lub path 279 Fix item description bug 284 Copy patched Cheat Defender Game Guard 289 Fix Homunculus attack AI 313 Change MapInfo*.lub path 322 Case-Insensitive Storage Search 323 Restore Songs Effect 326 Disable OTP Login Packet (Recommended) 328 Enable 44.1 kHz Audio Sampling Frequency 334 Remove Hardcoded HTTP IP 338 Additional client validation (Recommended) 347 Disable OS Privileges execution level 348 Send client flags to server (Recommended) 351 Translate arrows buttons text from korean to english 362 Fixes the Korean Job name issue with LangType (Recommended) 399 Set high priority class for active client 400 Set normal priority class for inactive client 404 Use borderless mode in full screen (Recommended) 416 Fix Tetra Vortex 427 Check is servertype in xml file was set to correct value (Recommended) 12.) Click the "Load Client" button at the bottom.13.) Click the "Load Profile" button to the right of it. Select and open the "profile.log" file just created.14.) Some modifications require input. As each prompt appears, edit them as follows: DATA.INI System/itemInfo_EN.lua 100 System\achievement_list_EN.lub System/Towninfo_EN.lub System\PetEvolutionCln_true_E.lub System/tipbox_EN.lub System/CheckAttendance_EN.lub System\OngoingQuestInfoList_True_EN System\RecommendedQuestInfoList_True_EN System\PrivateAirplane_T_EN.lub System\mapInfo_true_EN.lub Using wrong servertype in clientinfo/sclientinfo xml. Please change servertype to correct one. Note: You'll notice how two of them don't ask for a file extension, which is why we leave it off. That is not erroneous.15.) You should have 70 enabled patches when finished. Click "Apply Selected". Close Nemo.16.) Clean up the "\client" directory by deleting the following no longer required files: \AI_sakray \AuthModuleCache \client \db \doc \HShield \PatchClient 2020-04-01bRagexe_patched.exe.db 2020-04-01bRagexe_patched.exe.txt 2020-04-01bRagexe_patched.exe.secure.txt aossdk.dll ASPLnchr.exe bz32ex.dll CDResFileList.dat dbghelp.dll FORMAT.CFG GameGuard.des IFU13.inf IFU19.inf IFU7A.inf IFUEC.inf Init.exe KOR_LANG.CFG lua.exe mirrors.json NPCHK.DLL NPCIPHER.DLL npkcrypt.dll npkcrypt.sys npkcrypt.vxd npkcusb.sys npkeysdk.dll npkpdb.dll NPPSK.DLL NPSCAN.DES npupdate.dll NPUPDATE0.DLL NPX.DLL opensetup.ini.sample Patch.inf patchRE.inf Patchup.exe Patchup_RE.exe Ragexe.exe RagexeRE.exe RagHash.dat RagnarokKR.inf rsu-kro-rag-lite.exe rsu-kro-rag-lite.ini rsu-kro-renewal-lite.exe rsu-kro-renewal-lite.ini SavePath_Rag.exe SavePath_Sak.exe Setup.exe suipre.dll supdate.log v3hunt.dll Note: This should leave you with 58 files inside "\client". (8 folders + 50 misc)17.) Go to "\client\data". Open "clientinfo.xml". Change it too: <?xml version="1.0" encoding="euc-kr" ?> <clientinfo> <desc>Ragnarok Client Information</desc> <servicetype>korea</servicetype> <servertype>primary</servertype> <connection> <display>GoblinRO</display> <address>192.168.1.130</address> <port>6900</port> <version>55</version> <langtype>0</langtype> </connection> <connection> <display>OpenKore</display> <address>127.0.0.1</address> <port>6901</port> <version>55</version> <langtype>0</langtype> </connection> </clientinfo> Note: Inside the first <connection> block, change the <display> name and <address> to match your server. If WAN, you can use services like No-IP.18.) Go to "\client". Execute "opensetup.exe". (decline Telemetry prompt) Change the options to match your wants and needs. (graphics device, resolution, etc)Note: I personally like 1280x720 when playing in a window. Specifically while using X-Kore which we'll cover later.[ The OpenKore Client: Packet Extraction, Configuration, and Field Updating ] [ Best Client ]Note: Steps 1 and 2 are educational. Worth learning but can be skipped as I've already done this for you.01.) Extract Winsock Packet Editor (WPE). Allow the executable if Windows Defender or your anti-virus software flags it.02.) Using "WPE PRO - modified.exe" follow the Openkore Wiki Connectivity Guide to obtain master version and version number. (screenshot)03.) Extract OpenKore.04.) Go to "\openkore\tables" then open "servers.txt". Find "[Localhost]" towards the bottom. Replace with: [Localhost] ip 192.168.1.130 port 6900 private 1 master_version 0 version 128 charBlockSize 155 serverType kRO_RagexeRE_2020_04_01b serverEncoding Western addTableFolders kRO/RagexeRE_2020_04_01b;translated/kRO_english;kRO Note: Change the IP address to match your server. If WAN, you can use services like No-IP.05.) Go to "\openkore\fields". You'll notice inside are a number of folders labelled by episode number. You're going to want to take all the files out of each of these episodic folders and move them up a directory. Overriding the ones currently in your "\openkore\fields" folder.Note: We're doing this so that the bot can understand the map layouts of the newer content. The rAthena emulator is always improving but currently at the time of posting goes all the way to Episode 18. You might notice the bot is currently only developed up to Episode 17.1. If you play that far then you'll probably have a good idea on making the bot work in uncharted waters. For now, don't worry about it one bit. You're good for a loooooong time. Hell they'll probably have it included by the time you make it there.[ Logging Into Your Server, Making a GM Account, and Playing! ]Note: Even if you want to go straight to using OpenKore, we're going to use the kRO client to finish off the server and make our first accounts. While these steps can be done in OpenKore, it's easier to just follow along using a visual interface for now. If you've picked this project up at a later date, then make sure you've started the rAthena servers. (go to "\rathena", execute "runserver.bat")Using the kRO Client:01.) Go to "\client" and execute "2020-04-01bRagexe_patched.exe".02.) Select "GoblinRO" when prompted. (the server name you entered previously)03.) At the login screen type "admin_M" to make a new account on the server. You need to enter a 6+ digit password as well. (123456)Note: The first account is always a GM account. This has a different set of sprites used that are not compatible with actually wanting to play the game. They look cool because on the off chance you actually crossed one it needed to be unique. Generally you only saw one if you were about to get banned for botting or hacking so it was quite the event to casually see an admin. LOL!04.) Make a new character you're going to use to pwn rule breakers. Once in game, hit escape, then click "exit to windows".05.) Open Laragon. Click Database. Click "Open" in the new window.06.) Expand the "ragnarok" database. Click "login" again like we did in Step 25 of setting up rAthena. Click the "data" tab.07.) Look for the newly created admin account under the server account. Change it's "group_id" to 99. (now has full GM powers)08.) Close these windows. Go back to having Laragon running in your system tray.09.) Once again head to "\client" and execute "2020-04-01bRagexe_patched.exe".10.) At the login screen let's make a real account to actually play on. Once again, "yourname_M" or "yourname_F" (male or female) to make a new account on the server.Note: The sex you select here is only used for account management and does not effect the sex of your characters you make in game. It's pretty much pointless.11.) Spend extra time picking the right hair style, color, sex, and race. This is your new character!!12.) Play the game!Note: Future logins do not require the _M or _F after your account name. This is only done the first time to register a new account on the server from inside the client. You can also register accounts with the Flux Control Panel if you like. If you ever want to delete a character, it'll ask you for your email address as a security check to confirm. Accounts created in client automatically get registered with "[email protected]" as their email address in the database.Using the OpenKore Client:01.) Go to "\openkore\control". Open "config.txt".02.) Line 6: add "Localhost".03.) Line 7: add "0".04.) Line 8: add "Goblin". (your username) (do not add _M or _F)05.) Line 9: add "123456". (your password)06.) Line 11: add "0". (number / position of your character)07.) Save file.08.) Go to "\openkore" and execute "wxstart.exe". (wait for it to process maps and finish loading)09.) Play the game!Note: OpenKore does not currently support the new character start maps. It'll just throw errors in the console about not being able to navigate. Use the kRO client to at least get out of the introduction area. You can walk directly through the beginning and board the ship to Izlude. It's not required to interact with anything if you don't want to. There is stuff to do though, up to you.Using OpenKore inside kRO via X-Kore:01.) Go to "\openkore\control". Open "config.txt".02.) Line 23: change "0" to "3".03.) Line 30: change "ragexe.exe" to "2020-04-01bRagexe_patched".04.) Save file.05.) Go to "\openkore" and execute "wxstart.exe". (wait for it to finish loading)06.) Go to "\client" and execute "2020-04-01bRagexe_patched.exe".07.) Select "OpenKore" when prompted.08.) Login via your normal username and password for the account.09.) Select your character at the next screen.10.) Play the game with two clients at once!Note: I highly suggest running kRO in windowed mode for ease of use. This way you can bounce back and forth between the clients effortlessly. You do not need to keep the kRO or OpenKore windows as a focused priority. You can literally open other applications on top of both without any pause to the botting. You'll hear it in the background still playing the game while you're reading the wiki, checking email, or just doing whatever you please.[ Troubleshooting The Situation ]Note: Having an odd problem loading software at any point? Getting an error and not sure why? I'm not sure why either so give this a whirl.01.) Extract "Visual-C-Runtimes-All-in-One-Feb-2022.zip"02.) Execute "install_all.bat".03.) Wait for it to finish.04.) ??? Try Again ???05.) Probably Success.[ Packaging It Up For Transportation ]01.) Make a new folder called "GoblinRO". (or whatever you like)02.) Place your "\laragon", "\rathena", "\client", & "\openkore" folders inside it.03.) Make a new folder inside called "troubleshooting".04.) Copy "Visual-C-Runtimes-All-in-One-Feb-2022.zip" into "\troubleshooting".05.) Compress your "GoblinRO" folder. (zip/rar)Note: Transportation or not, I suggest you make a backup like this once you're finished. Always a good idea! Also compressing it greatly helps transfer times to things like USB drives or across networks. Not only is the file size reduced from around 5.5GB to 3.9GB but the fact that it doesn't have to work with the insane amount of small files present is a life saver. Remember you can always just extract the /client or /openkore folder if you're on computers that aren't running the server.[ Post Install House Cleaning ]01.) Delete the Master List of downloaded files required for install. (18 files, 3.8GB)02.) Uninstall Microsoft Visual Studio 2022 Community Edition. (7.62GB)Note: You will lose your ability to compile the server again if you make future changes.[ Conclusion ]Alright! Way to make it to the end! I spent a week constructing this. Across that time, I reached out to a lot of the related discord servers and forums. Mainly making sure my instructions were correct and up to date. At most stops I was met with silence then a private message with a price tag. Anywhere from $10-100 an hour, just for their working knowledge of an old MMORPG. For truly custom work I do understand it, but for basics? It really only motivated me more to put this out.I'd like to help remove the ridiculous paywall that has slowly started to surround this information. Sure, this has been a deep dive into an esoteric world. This game is over twenty years old at this point. Though it saddens me to see information omitted or even removed in order to sell it back to people as a service. I think that's not only harmful but gating something we have all enjoyed for decades. This is just information, there is nothing deserving of your currency. Everyone should be able to do this, for free.I hope you have found this both helpful and educational! Feel free to translate into your local language and distribute. I have done three trial runs across different machines and have not had a problem. If you're experiencing issues check that you haven't missed a step. Need support? Check the forum, wiki, github, and discord for both rAthena and OpenKore. Still can't find a solution? Post here! I cannot guarantee a timely response but I will check back in occasionally and try to help out as much as I can. Thanks for reading! /cheers
  5. I need a small help for Easycores bg_common npc on BG 2.0 guys ... How can I make it disable on reload or OnInit ? and Start on my set hour ? like I tried adding OnClock below OnBGStartCommand: but nothing happen ..I want to schedule Normal bg on 12pm to 3pm and Happy hours schedule is different ...I keeps on announcing after I reload hehehe .... And also where can I set rewards or make it usable items ? I tried to reach out on @Easycore but I think he's busy. Thankyou //===== rAthena Script ======================================= // Extended Battleground //= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = // Date: // 10-10-2019 // By: // Easycore (Zephyrus, original author) // // Contact: // - Facebook: https://www.facebook.com/EasycoreRo/ // - rAthena: https://rathena.org/board/profile/16425-easycore/ // - Discord: Easycore#3412 //= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = // ============================================================================== // BattleGround System - Common NPCs // ============================================================================== // MapFlags // ********************************************************************* bat_room mapflag nomemo bat_room mapflag nowarpto bat_room mapflag nobranch bat_room mapflag nopenalty bat_room mapflag noteleport bat_room mapflag nosave SavePoint //bat_room mapflag allow_bg_items // Funcion no agregada [Easycore] // Mapflag Town is required to Join BG Queues bat_room mapflag town // Battleground Queue Handler // ********************************************************************* - script BG_Queue_Join -1,{ end; OnInit: // Configuration // ***************************************************** // Battleground Rotation - Main NPC name setarray .BG_Arenas$[0], "Conquest"; // Battleground Arena Name - for announcements setarray .BG_Names$[0], "Conquest"; // Minimum Players to start the BG setarray .BG_Min[0], 1; // Maximum Players per Team setarray .BG_Max[0], 50; // BG Message Colors setarray .BG_Color$[0], "0xFFA500"; setarray .BG_Color2[0], 0xFFA500; // Team Building Mode : 0 = Lineal | 1 = Random | 2 = Class Priority | 3 = Faction Mode | 4 = Team Color (by script set Bat_Team,N;) set .TeamMode, 2; // Happy Hour - 1: Enabled | 0: Disabled set .HappyHour, 1; // Happy Hour - Reward rates % set .HappyHourRates, 100 + 20; // +20% // Main Code // ***************************************************** set .BG_Count, getarraysize(.BG_Arenas$); set .BG_Queue, bg_queue_create("Battleground Arena","BG_Queue_Join::OnJoinEvent",80); set .VS_Queue, bg_queue_create("Free For All Arena","BG_Queue_Join::OnVersusJoin",80); set .HWE, 0; // Move to Next Arena if ($BG_Index >= .BG_Count) set $BG_Index,0; // Restart Rotation set .TotalArenas, getarraysize(.BG_Arenas$); set .BG_Arena$,.BG_Arenas$[$BG_Index]; set .Ready, 1; initnpctimer; // Rotation if BG don't start... Comment if you don't want to use this method /* Commands */ // Admin/GM Commands bindatcmd "bgstart","BG_Queue_Join::OnBGStartCommand",99,99; bindatcmd "bgstop","BG_Queue_Join::OnBGStopCommand",99,99; bindatcmd "bgmode","BG_Queue_Join::OnBGModeCommand",99,99; // [Easycore] bindatcmd "bgsize","BG_Queue_Join::OnBGSizeCommand",99,99; // [Easycore] bindatcmd "bghappyhour","BG_Queue_Join::OnBGHHCommand",99,99; // [Easycore] // Player Commands bindatcmd "joinbg","BG_Queue_Join::OnDoJoin",0,99; bindatcmd "leavebg","BG_Queue_Join::OnDoLeave",0,99; end; OnDoJoin: // @joinbg if (getbattleflag("bg_eAmod_mode") == 0) { message strcharinfo(0),"Battlegrounds are currently disabled."; end; } else if (agitcheck() || agitcheck2()) { dispbottom "[Battleground is currently disabled for this moment due to War of Emperium.]"; end; } else if (checkquest(8600,PLAYTIME) == 2) { erasequest 8600; } else if (checkquest(8600,PLAYTIME) == 0) { dispbottom "[You are a Deserter. You can't participate until the indicator goes off]"; end; } bg_queue_join .BG_Queue; end; OnDoLeave: // @leavebg bg_queue_leave .BG_Queue; end; // Easycore // @bgmode <1-10> OnBGModeCommand: .@x = atoi(.@atcmd_parameters$[0]); if (.@x <= .TotalArenas+1 && .@x > 0) { if (.@x == 1) set $BG_Index, rand(.TotalArenas)-1; else set $BG_Index, .@x-3; message strcharinfo(0),"["+.BG_Names$[$BG_Index+1]+"] has been set."; donpcevent "BG_Queue_Join::OnRotate"; end; } else { message strcharinfo(0), "Usage: @bgmode <1-"+(.TotalArenas+1)+">"; dispbottom "#1 - Random",0xFFFFFF; for (.@i = 0; .@i<.TotalArenas; .@i++) dispbottom "#"+(.@i+2)+" - "+.BG_Names$[.@i],.BG_Color2[.@i]; end; } // @bgsize <1-10> <min> <max> OnBGSizeCommand: .@x = atoi(.@atcmd_parameters$[0]); .@x2 = atoi(.@atcmd_parameters$[1]); .@x3 = atoi(.@atcmd_parameters$[2]); if (.@x2 == 0 || .@x3 == 0) { message strcharinfo(0), "Usage: @bgsize <0-"+.TotalArenas+"> <min players> <max players>"; dispbottom "#0 - All Arenas",0xFFFFFF; for (.@i = 0; .@i<.TotalArenas; .@i++) dispbottom "#"+(.@i+1)+" - "+.BG_Names$[.@i],.BG_Color2[.@i]; end; } else if (.@x2 > .@x3) { message strcharinfo(0), "@bgsize failed: min players is higher than max players. "; end; } if (.@x <= .TotalArenas && .@x > 0) { message strcharinfo(0),"["+.BG_Names$[.@x-1]+"] min players is <"+.@x2+"> and max players is <"+.@x3+">."; setarray .BG_Min[.@x-1],.@x2; setarray .BG_Max[.@x-1],.@x3; } else { message strcharinfo(0),"[All Arenas] min players is <"+.@x2+"> and max players is <"+.@x3+">."; setarray .BG_Min[0],.@x2,.@x2,.@x2,.@x2,.@x2,.@x2,.@x2,.@x2,.@x2; setarray .BG_Max[0],.@x3,.@x3,.@x3,.@x3,.@x3,.@x3,.@x3,.@x3,.@x3; } end; // @bghappyhour OnBGHHCommand: if (.HappyHour == 0) { message strcharinfo(0),"Happy Hour is currently disabled."; end; } if (getbattleflag("bg_eAmod_mode") == 0) { message strcharinfo(0),"Battlegrounds are currently disabled."; end; } if (!.HWE) donpcevent "BG_Queue_Join::OnDoHappyHour"; else donpcevent "BG_Queue_Join::OnEndHappyHour"; end; OnBGStartCommand: if (getbattleflag("bg_eAmod_mode") == 1) { message strcharinfo(0),"Battlegrounds is already enabled."; end; } setbattleflag "bg_eAmod_mode", 1; message strcharinfo(0),"Battlegrounds have been enabled."; donpcevent "BG_Queue_Join::OnRotate"; callsub OnEndArena; OnBGStopCommand: setbattleflag "bg_eAmod_mode", 0; set .HWE, 0; setbattleflag "bg_reward_rates",100; // Normal Rates message strcharinfo(0),"Battlegrounds have been disabled."; .@msg$ = "[Battlegrounds] Arenas and Queuing have been disabled by a Game Master."; announce .@msg$, 0, 0x00FFFF, 0x190, 12, 100, 100; if ($@BG_Status != 0) donpcevent .BG_Arena$+"::OnMatchEnd"; callsub OnEndArena; OnEndArena: set $@BG_Status, 0; if ($@BG_Team1 == 0 && $@BG_Team2 == 0 && $@BG_Team3 == 0) end; // Warps Teams bg_warp $@BG_Team1,"bat_room",155,150; bg_warp $@BG_Team2,"bat_room",155,150; bg_warp $@BG_Team3,"bat_room",155,150; // Destroy Teams bg_destroy $@BG_Team1; set $@BG_Team1, 0; bg_destroy $@BG_Team2; set $@BG_Team2, 0; bg_destroy $@BG_Team3; set $@BG_Team3, 0; OnRotate: OnTimer10000: // Rotation if BG don't start... Comment if you don't want to use this method. 120 = 2 Minutes // Check if BG is enabled/disabled [Easycore] if (getbattleflag("bg_eAmod_mode") == 0) end; // Move to Next Arena if (set($BG_Index,$BG_Index + 1) >= .BG_Count) set $BG_Index,0; // Restart Rotation set .BG_Arena$,.BG_Arenas$[$BG_Index]; initnpctimer; // Rotation if BG don't start... Comment if you don't want to use this method OnJoinEvent: if ($@BG_Status == 2) end; // BG Ending... Must wait until OnRotate is called set .@Queue_Count, bg_queue_data(.BG_Queue,0); switch($@BG_Status) { case 0: // Idle - Ready to Start if (.BG_Arena$ == "Tierra_TI") set .@Req, .BG_Min[$BG_Index] * 3; else set .@Req, .BG_Min[$BG_Index] * 2; if (bg_queue_checkstart(.BG_Queue,.TeamMode,((.BG_Arena$ == "Tierra_TI") ? 3 : 2),.BG_Min[$BG_Index])) { donpcevent .BG_Arena$ + "::OnBuildTeams"; // Fill Teams with Queue Members if (.BG_Arenas$[$BG_Index] == "Tierra_TI") bg_queue2teams .BG_Queue,.BG_Min[$BG_Index],.BG_Max[$BG_Index],.TeamMode,$@BG_Team1,$@BG_Team2,$@BG_Team3; else bg_queue2teams .BG_Queue,.BG_Min[$BG_Index],.BG_Max[$BG_Index],.TeamMode,$@BG_Team1,$@BG_Team2; stopnpctimer; // Rotation if BG don't start... Comment if you don't want to use this method set $@BG_Status,1; set .@msg$, "Battleground -- " + .BG_Names$[$BG_Index] + " -- Begining"; bgannounce .@msg$,.BG_Color$[$BG_Index]; donpcevent .BG_Arena$ + "::OnReady"; } else { set .@msg$, "Battleground -- " + .BG_Names$[$BG_Index] + " -- " + (.@Req - .@Queue_Count) + " more players to start."; bgannounce .@msg$,.BG_Color$[$BG_Index]; } break; case 1: // Running - Others can join if (.@Queue_Count > 0) { if (.BG_Arena$ == "Tierra_TI") { bg_balance_teams .BG_Queue,.BG_Max[$BG_Index],.TeamMode,$@BG_Team1,$@BG_Team2,$@BG_Team3; set .@BG_Count1, bg_get_data($@BG_Team1,0); set .@BG_Count2, bg_get_data($@BG_Team2,0); set .@BG_Count3, bg_get_data($@BG_Team3,0); set .@msg$, "Battleground -- " + .BG_Names$[$BG_Index] + " -- B: " + .@BG_Count1 + "/" + .BG_Max[$BG_Index] + ", R: " + .@BG_Count2 + "/" + .BG_Max[$BG_Index] + ", G: " + .@BG_Count3 + "/" + .BG_Max[$BG_Index] + " (Playing)"; } else { bg_balance_teams .BG_Queue,.BG_Max[$BG_Index],.TeamMode,$@BG_Team1,$@BG_Team2; set .@BG_Count1, bg_get_data($@BG_Team1,0); set .@BG_Count2, bg_get_data($@BG_Team2,0); set .@msg$, "Battleground -- " + .BG_Names$[$BG_Index] + " -- B: " + .@BG_Count1 + "/" + .BG_Max[$BG_Index] + ", R: " + .@BG_Count2 + "/" + .BG_Max[$BG_Index] + " (Playing)"; } bgannounce .@msg$,.BG_Color$[$BG_Index]; } break; } end; OnVersusJoin: if ($@VS_Status != 0) end; set .@Queue_Count, bg_queue_data(.VS_Queue,0); if (.@Queue_Count >= 10) { donpcevent "FFA_Arena::OnBuildTeams"; bg_queue2teams .VS_Queue,1,1,0,$@VS_Team[0],$@VS_Team[1],$@VS_Team[2],$@VS_Team[3],$@VS_Team[4],$@VS_Team[5],$@VS_Team[6],$@VS_Team[7],$@VS_Team[8],$@VS_Team[9]; set $@VS_Status,1; announce "Battleground -- Free For All -- Begining",0,0x483D8B; donpcevent "FFA_Arena::OnReady"; } else announce "Battleground -- Free For All -- " + (10 - .@Queue_Count) + " more players to start",0,0x483D8B; end; OnFri0600: // Friday, 6 a.m. //rankreset 1; // Ranking Reset end; // BattleGround Happy Hour OnDoHappyHour: OnClock1600: OnClock2000: if (getbattleflag("bg_eAmod_mode") == 0 || .HappyHour == 0) end; set .HWE, 1; announce "-- Battleground Happy Hour has begun --",0,0x00FF00; setbattleflag "bg_reward_rates",.HappyHourRates; // +20% Reward Rates end; OnEndHappyHour: OnClock1800: OnClock2200: if (getbattleflag("bg_eAmod_mode") == 0 || .HappyHour == 0) end; set .HWE, 0; announce "-- Battleground Happy Hour is over --",0,0x00BFFF; setbattleflag "bg_reward_rates",100; // Normal Rates end; } // Registration NPC // ********************************************************************* - script BG_Register FAKE_NPC,{ if (getvariableofnpc(.Ready,"BG_Queue_Join") == 0) donpcevent "BG_Queue_Join::OnInit"; mes "[^FFA500Battle Recruiter^000000]"; mes "This is the Battleground Information and Registration service."; mes "What do you want to do?"; next; switch(select("^FFA500Battleground Arenas^000000:^0000FFFree For All Arena^000000:Warp to Battle Room")) { case 1: mes "[^FFA500Battle Recruiter^000000]"; mes "Battlegrounds Arena are different kinds of games where Teams fight for victory."; mes "What do you want to do?"; next; switch(select("Register:Party Register:Leave Queue:Battleground Help")) { case 1: if (BaseLevel < 80) { mes "[^FFA500Battle Recruiter^000000]"; mes "Min required level to join a battleground is 80."; close; } if (checkquest(8600,PLAYTIME) == 2) erasequest 8600; if (checkquest(8600,PLAYTIME) == 1) { mes "[^FFA500Battle Recruiter^000000]"; mes "You are a Deserter. You can't participate until the indicator goes off"; close; } mes "[^FFA500Battle Recruiter^000000]"; mes "Let's proceed with the registration..."; mes "You must wait on any City until BG starts."; mes "Close this window to continue..."; close2; bg_queue_join getvariableofnpc(.BG_Queue,"BG_Queue_Join"); end; case 2: if (getcharid(1) == 0) { mes "[^FFA500Battle Recruiter^000000]"; mes "You are not on a Party."; close; } mes "[^FFA500Battle Recruiter^000000]"; mes "Let's proceed with the registration..."; mes "You must wait on any City until BG starts."; mes "Close this window to continue..."; close2; bg_queue_partyjoin getcharid(1),getvariableofnpc(.BG_Queue,"BG_Queue_Join"); end; case 3: mes "[^FFA500Battle Recruiter^000000]"; mes "If you are registered, you will be removed."; mes "Are you sure?"; next; if (select("Yes, leave queue:No, I will stay") == 2) { mes "[^FFA500Battle Recruiter^000000]"; mes "Ok, nothing to change."; close; } mes "[^FFA500Battle Recruiter^000000]"; mes "Close this window to continue..."; close2; bg_queue_leave getvariableofnpc(.BG_Queue,"BG_Queue_Join"); end; case 4: mes "[^FFA500Battle Recruiter^000000]"; mes "Tell me... what battleground you don't understand?"; next; switch(select("Capture the Flag:Team DeathMatch:Stone Control:Eye of Storm:Bossnia:Domination:Triple Inferno:Conquest:Rush")) { case 1: mes "[^FFA500Battle Recruiter^000000]"; mes "The objective of the Flavius Battle CTF is to score 3 points before your enemy, by capture their Flag."; next; mes "[^FFA500Battle Recruiter^000000]"; mes "To capture a Flag you need to take the enemy flag, and bring it to your base flag."; next; mes "[^FFA500Battle Recruiter^000000]"; mes "If your base flag is captured too, you need to kill the flag carrier and take the flag back to your base."; break; case 2: mes "[^FFA500Battle Recruiter^000000]"; mes "Kill all the enemy players to let their Team without points."; mes "Protect our army."; break; case 3: mes "[^FFA500Battle Recruiter^000000]"; mes "Take the Stones in the middle of the battlefield and put in on your base, in the Stone Points."; next; mes "[^FFA500Battle Recruiter^000000]"; mes "Each Stone will give points to your team. First team reach 99 points wins the game."; next; mes "[^FFA500Battle Recruiter^000000]"; mes "Protect your stones from to be captured by the enemy."; break; case 4: mes "[^FFA500Battle Recruiter^000000]"; mes "There are two bases, North and South which teams can capture by holding position on the Base more than the other team."; next; mes "[^FFA500Battle Recruiter^000000]"; mes "Each base will give you points each 5 seconds of Domination. If your Team control both bases the amount of points increases."; next; mes "[^FFA500Battle Recruiter^000000]"; mes "To get aditional points, in the middle there is a Flag spawn, capture it and put it on any of your team Bases."; next; mes "[^FFA500Battle Recruiter^000000]"; mes "The first Team reach 99 points wins the match."; break; case 5: mes "[^FFA500Battle Recruiter^000000]"; mes "Attack the enemy base and destroy each MVP Guardian. To do damage to the guardian your team must capture the Balance Flag in the middle base."; next; mes "[^FFA500Battle Recruiter^000000]"; mes "Each team have 5 guardian to be protected or killed."; break; case 6: mes "[^FFA500Battle Recruiter^000000]"; mes "There are three bases, North, Center and South which teams can capture by holding position on the Base more than the other team."; next; mes "[^FFA500Battle Recruiter^000000]"; mes "Each base will give you points each 5 seconds of Domination."; next; mes "[^FFA500Battle Recruiter^000000]"; mes "The first Team reach 99 points wins the match."; break; case 7: mes "[^FFA500Battle Recruiter^000000]"; mes "There are 3 teams in the battlefield, your team and other 2 enemies."; next; mes "[^FFA500Battle Recruiter^000000]"; mes "Kill the enemy players, collect the skulls and bring then to the Sacrifice Totem to win points."; next; mes "[^FFA500Battle Recruiter^000000]"; mes "You can collect your own team skulls and bring then to your Sacrifice Totem to avoid other teams to score."; next; mes "[^FFA500Battle Recruiter^000000]"; mes "If you get killed all your skulls will be drop to the floor, including your own skull. First Team to get 80 points wins the battle."; break; case 8: mes "[^FFA500Battle Recruiter^000000]"; mes "If you are Attacking, destroy the enemy defenses and it's Flag."; next; mes "[^FFA500Battle Recruiter^000000]"; mes "If you are Defending, protect your castle defenses and the Flag."; break; case 9: mes "[^FFA500Battle Recruiter^000000]"; mes "Fight to capture the Castle and organize your team to defend it."; next; mes "[^FFA500Battle Recruiter^000000]"; mes "If you fail on the first capture, kill the defender and take it for your team."; break; } break; } close; case 2: mes "[^FFA500Battle Recruiter^000000]"; mes "Free For All Arena is a Duel between 10 players with No Teams."; mes "The target is to kill 25 players."; mes "What do you want to do?"; next; switch(select("Register:Leave Queue")) { case 1: if (BaseLevel < 80) { mes "[^FFA500Battle Recruiter^000000]"; mes "Min required level to join a battleground is 80."; close; } if (checkquest(8600,PLAYTIME) == 2) erasequest 8600; if (checkquest(8600,PLAYTIME) == 1) { mes "[^FFA500Battle Recruiter^000000]"; mes "You are a Deserter. You can't participate until the indicator goes off"; close; } mes "[^FFA500Battle Recruiter^000000]"; mes "Let's proceed with the registration..."; mes "You must wait on any City until BG starts."; mes "Close this window to continue..."; close2; bg_queue_join getvariableofnpc(.VS_Queue,"BG_Queue_Join"); end; case 2: mes "[^FFA500Battle Recruiter^000000]"; mes "If you are registered, you will be removed."; mes "Are you sure?"; next; if (select("Yes, leave queue:No, I will stay") == 2) { mes "[^FFA500Battle Recruiter^000000]"; mes "Ok, nothing to change."; close; } mes "[^FFA500Battle Recruiter^000000]"; mes "Close this window to continue..."; close2; bg_queue_leave getvariableofnpc(.VS_Queue,"BG_Queue_Join"); end; } break; case 3: mes "[^FFA500Battle Recruiter^000000]"; mes "May the War God bless you."; close2; warp "bat_room",155,150; end; } end; } //bat_room,160,150,3 duplicate(BG_Register) Battle Recruiter#bat 4_F_JOB_KNIGHT prontera,123,83,3 duplicate(BG_Register) Battle Recruiter#prt 4_F_JOB_KNIGHT // General Guillaume // ********************************************************************* bat_room,160,159,3 script General Guillaume 4_M_KY_KIYOM,{ cutin "bat_kiyom2",2; mes "[General Guillaume]"; mes "Hot-blooded adventurer, we need your ability to win this battle."; next; cutin "bat_kiyom1",2; mes "[General Guillaume]"; mes "Our great king, Marcel Marollo VII, is very sick lately. His Majesty has declared that he chosen either me or Prince Croix as the next king amongst his 9 sons."; next; mes "[General Guillaume]"; mes "Two kings can't share a nation!"; mes "Only the one victorious from His Majesty's appointed battle will be enthroned."; next; mes "[General Guillaume]"; mes "This is however, not just a battle between us. This battle will determine the future of this country. I pledge on my honor to prove that I'm the one who can protect this Maroll from outside threats."; next; switch(select("Join the Blue Team","Join the Green Team","End Conversation")) { case 1: cutin "bat_kiyom2",2; mes "[General Guillaume]"; mes "Welcome to my army, comrade."; mes "Your eyes tell me that you're a soldier that I can trust."; set Bat_Team,1; next; mes "[General Guillaume]"; mes "Now, go upstairs and apply for battle with your comrades. I'm sure they'll welcome you whole-heartedly!"; break; case 2: cutin "bat_kiyom2",2; mes "[General Guillaume]"; mes "So you will take this fight as your own..."; mes "Then you are my enemy."; set Bat_Team,0; next; mes "[General Guillaume]"; mes "Go now, We will meet again in the Battlefield."; break; case 3: mes "[General Guillaume]"; mes "I'll be the one who will capture the flag!"; break; } close2; cutin "",255; end; } // General Croix // ********************************************************************* bat_room,160,140,3 script Prince Croix 4_M_CRU_CRUA,{ cutin "bat_crua1",2; mes "[Prince Croix]"; mes "Wise adventurer, why don't you lend us your power for victory?"; next; cutin "bat_crua2",2; mes "[Prince Croix]"; mes "I do not wish to shed blood, but I have no choice but to fight for the possibility of peace and for the sake of my people."; next; mes "[Prince Croix]"; mes "General Guillaume may have an advantage in this battle as he is the great general of Maroll, but that doesn't automatically mean he'll win. I want to win this battle so that I can grant a better future for my people."; next; switch(select("Join the Red Team","Join the Green Team","End Conversation")) { case 1: mes "[Prince Croix]"; mes "Thank you so much. I feel like I can win with the help of adventurers like you. Now, please go downstairs and join your comrades in sharpening their skills to fight the enemy!"; set Bat_Team,2; break; case 2: mes "[Prince Croix]"; mes "So you will take this fight as your own..."; mes "Then you are my enemy."; set Bat_Team,0; next; mes "[Prince Croix]"; mes "Go now, We will meet again in the Battlefield."; break; case 3: mes "[Prince Croix]"; mes "For Maroll!"; break; } close2; cutin "",255; end; } // Guard Dummy // ********************************************************************* bat_room,161,141,3 script Prince Croix's Aid::bat_aid 4_M_CRU_HEAD,{ end; } bat_room,161,139,3 duplicate(bat_aid) Prince Croix's Aid::bat_aid2 4_M_CRU_HEAD bat_room,161,160,3 duplicate(bat_aid) General Guillaume's Aid::bat_aid3 4_M_KY_HEAD bat_room,161,158,3 duplicate(bat_aid) General Guillaume's Aid::bat_aid4 4_M_KY_HEAD // Flags // ********************************************************************* - script Base Flag#bg FAKE_NPC,{ end; } // BattleGround Warper - Exit // ********************************************************************* bat_room,148,150,4 script Teleporter#bat 4_F_TELEPORTER,{ mes "[Teleporter]"; mes "Do you wish to leave the battlefield? Use my service to return to town."; next; if (select("Leave:Don't Leave") == 2) { mes "[Teleporter]"; mes "I'll be here whenever you're in need of my service."; close; } set .@spoint$, getsavepoint(0); set .@x, getsavepoint(1); set .@y, getsavepoint(2); mes "[Teleporter]"; mes "You will be sent back to " + .@spoint$ + "."; close2; warp .@spoint$, .@x, .@y; end; } // Kafra // ********************************************************************* bat_room,148,147,4 script Kafra Staff::kaf_bat 4_F_KAFRA9,{ cutin "kafra_09",2; callfunc "F_Kafra",0,2,1,150,0; } //== Badges Exchange ======================================= bat_room,160,150,3 script Erundek 4_M_MANAGER,{ if (checkweight(1201,1) == 0) { mes "- Wait a minute !! -"; mes "- Currently you're carrying -"; mes "- too many items with you. -"; mes "- Please try again -"; mes "- after you loose some weight. -"; close; } mes "[Erundek]"; mes "Do you have the battlefield badges?"; mes "I can exchange Bravery Badges and Valor Badges for reward items."; next; switch(select("Exchange Badges", "Check the Catalog")) { case 1: mes "[Erundek]"; mes "Which type of items would you like to exchange?"; mes "To check more information about the reward items, please use our ^3131FFCatalog^000000."; next; switch(select("Weapon", "Armor", "Accessory", "Consumable")) { case 1: mes "[Erundek]"; mes "You chose ^3131FFWeapon^000000."; mes "The following weapons are available for exchange with the battlefield badges."; mes "Please note that items for ^3131FFBravery Badges are indicated as (BB)^000000, and ^3131FFValor Badges as (VB)^000000."; next; switch(select("Dagger/OneSword/TwoSword/TwoSpear", "Staff/Mace/TwoAxe/Shuriken", "Bow/Katar/Music/Whip", "Book/Knuckle", "Revolver/Rifle/Gatling/Shotgun/Launcher")) { case 1: mes "[Erundek]"; mes "The following items are available in the ^3131FFDagger, One-Handed Sword, Two-Handed Sword, and Two-Handed Spear^000000 category."; next; setarray .@Weapons[0],13036,7828,13037,7829,13411,7828,13410,7829,1183,7828,1184,7829,1425,7828,1482,7829; break; case 2: mes "[Erundek]"; mes "The following items are available in the ^3131FFStaff / Mace / Two-Handed Axe / Huuma Shuriken^000000 category."; next; setarray .@Weapons[0],1632,7828,1633,7829,1634,7828,1635,7829,1543,7828,1542,7829,1380,7828,1379,7829,13305,7828,13306,7829; break; case 3: mes "[Erundek]"; mes "The following weapons are available in the ^3131FFBow / Katar / Musical Instrument / Whip^000000 category."; next; setarray .@Weapons[0],1739,7828,1738,7829,1279,7828,1280,7829,1924,7828,1923,7829,1978,7828,1977,7829; break; case 4: mes "[Erundek]"; mes "The following weapons are available in the ^3131FFBook / Knuckle^000000 category."; next; setarray .@Weapons[0],1574,7828,1575,7829,1824,7828,1823,7829; break; case 5: mes "[Erundek]"; mes "The following weapons are available in the ^3131FFRevolver / Rifle / Gatling Gun / Shotgun / Grenade Launcher^000000 category."; next; setarray .@Weapons[0],13108,7828,13171,7829,13172,7828,13173,7829,13174,7829; break; } .@menu$ = ""; for (.@i = 0; .@i < getarraysize(.@Weapons); .@i += 2) .@menu$ += getitemname(.@Weapons[.@i])+((.@Weapons[.@i+1]==7828)?"(BB)":"(VB)")+":"; .@i = (select(.@menu$)-1)*2; .@type$ = ((.@Weapons[.@i+1]==7828)?"(BB)":"(VB)"); mes "[Erundek]"; mes "You chose ^3131FF"+getitemname(.@Weapons[.@i])+.@type$+"^000000."; mes "You can exchange for this item with ^FF0000100 "+getitemname(.@Weapons[.@i+1])+"^000000."; mes "Would you like to exchange?"; next; switch(select("Do not exchange", "Exchange")) { case 1: break; case 2: mes "[Erundek]"; mes "Would you like to spend ^FF0000100 "+getitemname(.@Weapons[.@i+1])+"^000000 and receive a ^3131FF"+getitemname(.@Weapons[.@i])+.@type$+"^000000?"; next; mes "[Erundek]"; mes "Remember, Battleground Reward Items are ^FF0000Character Bound^000000. Are you sure you want this item?"; next; switch(select("Yes", "No")) { case 1: mes "[Erundek]"; if (countitem(.@Weapons[.@i+1]) >= 100) { mes "Thank you for exchanging."; delitem .@Weapons[.@i+1],100; getitem .@Weapons[.@i],1; } else mes "I'm sorry, but you don't have enough badges to exchange."; close; case 2: break; } break; } mes "[Erundek]"; mes "Do you need more time to check the items?"; close; case 2: mes "[Erundek]"; mes "You chose ^3131FFArmor^000000."; mes "The following armors are available for exchange with the battlefield badges."; next; switch(select("Garments / Shoes", "Armor")) { case 1: setarray .@items[0],2538,50,2539,50,2540,50,2435,50,2436,50,2437,50; break; case 2: setarray .@items[0],2376,80,2377,80,2378,80,2379,80,2380,80,2381,80,2382,80; break; } break; case 3: mes "[Erundek]"; mes "You chose ^3131FFAccessory^000000."; mes "You can exchange the Medal of Honors with your Badges according to the job classes, as follows:"; next; setarray .@items[0],2733,500,2720,500,2721,500,2722,500,2723,500,2724,500,2725,500; .@menu1$ = "Gunslinger:Swordman/Taekwon Master:Thief:Acolyte:Magician:Archer:Merchant"; break; case 4: mes "[Erundek]"; mes "You chose ^3131FFConsumable^000000."; mes "The following consumable items are available for exchange with the battlefield badges:"; next; setarray .@items[0],12269,10,12270,10,12271,5,12272,10,12273,10; break; } break; case 2: mes "[Erundek]"; mes "We have many items, so please take a look and purchase deliberately."; close2; readbook 11010,1; end; } .@menu$ = ""; if (.@menu1$ != "") .@menu$ = .@menu1$; else for (.@i = 0; .@i < getarraysize(.@items); .@i += 2) .@menu$ += getitemname(.@items[.@i])+":"; .@i = (select(.@menu$)-1)*2; mes "[Erundek]"; mes "You chose ^3131FF"+getitemname(.@items[.@i])+"^000000."; switch(.@items[.@i]) { case 2720: mes "This item is for Swordman and Taekwon Master Class only."; break; case 2721: mes "This item is for Thief Class only."; break; case 2722: mes "This item is for Acolyte Class only."; break; case 2723: mes "This item is for Magician Class only."; break; case 2724: mes "This item is for Archer Class only."; break; case 2725: mes "This item is for Merchant Class only."; break; case 2733: mes "This item is for Gunslinger only."; break; default: break; } mes "You can exchange for this item with ^FF0000"+.@items[.@i+1]+" "+getitemname(7828)+" or "+.@items[.@i+1]+" "+getitemname(7829)+"^000000."; mes "Would you like to exchange?"; next; switch(select("Do not exchange", "Exchange")) { case 1: mes "[Erundek]"; mes "Do you need more time to check the items?"; break; case 2: mes "[Erundek]"; mes "Which Badge do you want to exchange?"; mes "You need ^3131FF"+.@items[.@i+1]+" Badges^000000 to exchange."; next; if (.@item[0] < 12269 || .@item[0] > 12273) { mes "[Erundek]"; mes "Remember, Battleground Reward Items are ^FF0000Character Bound^000000. Are you sure you want this item?"; next; } .@j = select("Bravery Badge", "Valor Badge", "Cancel"); mes "[Erundek]"; if (.@j == 3) { mes "You cancelled the exchange."; break; } .@cost = ((.@j==1)?7828:7829); if (countitem(.@cost) >= .@items[.@i+1]) { mes "Thank you for exchanging."; delitem .@cost, .@items[.@i+1]; getitem .@items[.@i],1; } else mes "You do not have enough "+getitemname(.@cost)+"s."; break; } close; } bat_room,160,148,3 script Telma 701,{ mes "[Telma]"; mes "Welcome, mighty warrior."; mes "Do you need supplies for your battles?"; mes "I can exchange supplies for your badges..."; next; switch(select("150 Condensed White Potion:90 Blue Potion:3 Poison Bottle:30 Fire Bottle:30 Acid Bottle:30 Plant Bottle:30 Marine Sphere Bottle:15 Glistening Coat:50 Yellow Gemstone:50 Red Gemstone:100 Blue Gemstone:5 Speed Potion:20 Cobweb")) { case 1: callsub S_BuyConsumableBG,547,150; // Condensed White Potion case 2: callsub S_BuyConsumableBG,505,90; // Blue Potion case 3: callsub S_BuyConsumableBG,678,3; // Poison Bottle case 4: callsub S_BuyConsumableBG,7135,30; // Fire Bottle case 5: callsub S_BuyConsumableBG,7136,30; // Acid Bottle case 6: callsub S_BuyConsumableBG,7137,30; // Plant Bottle case 7: callsub S_BuyConsumableBG,7138,30; // Marine Sphere Bottle case 8: callsub S_BuyConsumableBG,7139,15; // Glistening Coat case 9: callsub S_BuyConsumableBG,715,50; // Yellow Gemstone case 10: callsub S_BuyConsumableBG,716,50; // Red Gemstone case 11: callsub S_BuyConsumableBG,717,100; // Blue Gemstone case 12: callsub S_BuyConsumableBG,12016,5; // Speed Potion case 13: callsub S_BuyConsumableBG,1025,20; // Cobweb } end; S_BuyConsumableBG: set .@item_id, getarg(0); set .@amt, getarg(1); mes "[Telma]"; mes "Do you want it for?..."; next; if (select("~ Battleground:~ War of Emperium") == 1) .@bg_item = 1; mes "[Telma]"; mes "How many sets of ^0000FF"+ .@amt +" "+ getitemname(.@item_id) +"s^000000 do you want?"; mes "1 = "+ .@amt +" supplies = 1 badge"; mes "2 = "+ .@amt*2 +" supplies = 2 badges"; mes "3 = "+ .@amt*3 +" supplies = 3 badges"; mes "etc.."; next; input .@sets; mes "[Telma]"; if (.@sets < 1) { mes "Enter a positive amount, greater than zero."; close; } mes "So you want ^0000FF"+ (.@amt*.@sets) +" "+ getitemname(.@item_id) +"s^000000..."; mes "Remember these can only be used in "+((.@item_id)?"BattleGround":"WoE Maps"); mes "It will cost you "+ .@sets +" badge(s)..."; next; switch(select("Give her "+ .@sets +" Bravery Badge(s):Give her "+ .@sets +" Valor Badge(s):Give her "+ (3*.@sets) +" Heroism Badges")) { case 1: set .@badge,7828; set .@cost,1; break; case 2: set .@badge,7829; set .@cost,1; break; case 3: set .@badge,7773; set .@cost,3; break; } .@bgchar = getBattleFlag("bg_reserved_char_id"); .@woechar = getBattleFlag("woe_reserved_char_id"); mes "[Telma]"; if (countitem(.@badge) < (.@cost*.@sets)) { mes "You do not have enough ^FF0000"+getitemname(.@badge)+"s^000000 to buy "+(.@amt*.@sets)+" "+getitemname(.@item_id)+"s."; } else if (!checkweight(.@item_id, .@amt*.@sets)) { mes "You are overweight or have too many items in your inventory."; } else { delitem .@badge, .@cost*.@sets; if (.@bg_item) // Battleground's Consumables getitem2 .@item_id,(.@amt*.@sets),1,0,0, 254, 0, .@bgchar & 0xFFFF, .@bgchar >> 0x10; else getitem2 .@item_id,(.@amt*.@sets),1,0,0, 254, 0, .@woechar & 0xFFFF, .@woechar >> 0x10; mes "Here are your: ^0000FF"+(.@amt*.@sets)+" "+getitemname(.@item_id)+"s^000000!"; mes "Remember they can only be used in "+((.@item_id)?"BattleGround":"WoE Maps"); } close; }
  6. im having this on my console [Debug]: Source (NPC): Breaker Ladder at prontera (171,179) [Error]: buildin_sleep2: no unit is attached [Debug]: Source (NPC): Emperium Breaker at prontera (173,176) [Error]: buildin_sleep2: no unit is attached here is the script i used prontera,173,176,4 script Emperium Breaker 743,{ // What Map will be used set .Map$,"job3_arch01"; // How many Top Breaker will be Recorded set .TopRank,10; // Message to Inform Players while inside the Room setarray .Instruction$[0], "Please Listen here carefully.", "This is Emperium Breaker Test Room , which is use to test your Breaking Time.", "Prepare youself...and do your best to Break it...", "Okay that's All i want to say , get Ready yourself and it will Start Soon."; while( 1 ){ mes "This is Emperium Breaker test Room. "; mes "You are able to calculate your Emperium Breaking Speed in this Room."; next; switch( select( ( getmapusers( .Map$ ) )?"^FF0000NOT Available":"^0000FFAvailable^000000", "Top ^FF0000"+.TopRank+"^000000 Breaker Ladder", ( getgmlevel() < 90 )?"":"^FF0000[GM]^000000 Reset Room", ( getgmlevel() < 90 )?"":"^FF0000[GM]^000000 Reset Ladder" )){ Case 1: if( getmapusers( .Map$ ) ){ mes "There is another player inside it now."; next; break; } warp .Map$,0,0; killmonster .Map$,"All"; // removemapflag .Map$,mf_noskill; donpcevent strnpcinfo(0)+"::OnReady"; end; Case 2: mes "^ED1ADCLatest Record^000000 : "+LatestRecord/1000+"."+LatestRecord%1000+" Seconds."; for( set .@i,0; .@i < .TopRank; set .@i,.@i + 1 ){ if( !$TopRankTime[.@i] ) break; mes "^FF0000Top "+( .@i + 1 )+" : ^0000FF"+$TopName$[.@i]+" "; mes "^FF0000Time Taken : ^ED1ADC[ "+$TopRankTime[.@i]/1000+"."+$TopRankTime[.@i]%1000+" Sec. ]^000000 "; } next; break; Case 3: mapannounce .Map$,"A GM has RESET the Breaker Test Room.",0,0x00FF00; killmonster .Map$,"All"; sleep2 3000; mapwarp .Map$,"prontera",156,175; mes "Done Reset. and Player who are inside are warped out."; next; break; Case 4: switch( select( "^0000FFAll Player^000000:^FF0000One Player^000000" ) ){ Case 1: deletearray $TopRankTime[0],getarraysize( $TopRankTime ); deletearray $TopName$[0],getarraysize( $TopName$ ); mes "RESETED WHOLE LADDER."; break; Case 2: mes "Please input the ^FF0000EXACT NAME^000000 of player you want to delete."; input .Name$; for( set .@i,0; .@i < .TopRank; set .@i,.@i + 1 ){ if( .Name$ == $TopName$[.@i] ){ deletearray $TopName$[.@i],1; deletearray $TopRankTime[.@i],1; mes "Removed ^FF0000"+.Name$+"^000000 from the List."; } } } next; break; } } OnReady: sleep2 3000; for( set .@i,0; .@i < getarraysize( .Instruction$ ); set .@i,.@i + 1 ){ mapannounce .Map$,.Instruction$[.@i],0,0x00FF00; sleep2 2500; } for( set .@i,5; .@i > 0; set .@i,.@i - 1 ){ mapannounce .Map$,"Count Down : "+.@i+" Seconds.",0,0x00FF00; sleep2 1000; } //mapannounce .Map$,"Hit the Emperium Now and Skills Disabled.",0,0x00FF00; setmapflag .Map$,mf_noskill; monster .Map$,29,27,"Breaker Test",1288,1,strnpcinfo(0)+"::OnBreaked"; set .Record,0; sleep2 500; initnpctimer; end; OnTimer600000: if( !mobcount( .Map$,strnpcinfo(0)+"::OnBreaked" ) ) end; mapannounce .Map$,"You spent too much time. i think you are AFK , so you are out.",0,0xED1ADC; sleep2 3000; mapwarp .Map$,"prontera",156,175; stopnpctimer; end; OnBreaked: set .Time,getnpctimer(0); copyarray .@tempName$[0],$TopName$[0],getarraysize( $TopName$ ); copyarray .@tempRecord[0],$TopRankTime[0],getarraysize( $TopRankTime[0] ); set LatestRecord,.Time; for( set .@i,0; .@i < .TopRank; set .@i,.@i + 1 ){ if( .Time < $TopRankTime[.@i] || !$TopRankTime[.@i] ){ set $TopRankTime[.@i],.Time; set $TopName$[.@i],strcharinfo(0); copyarray $TopRankTime[.@i + 1],.@tempRecord[0],getarraysize( .@tempRecord ); copyarray $TopName$[.@i + 1],.@tempName$[0],getarraysize( .@tempName$ ); announce "[ "+strcharinfo(0)+" ] Achieved Top "+( .@i + 1 )+" in Emperium Breaking with "+.Time/1000+"."+.Time%1000+" Seconds !!!",bc_all,0xED1ADC; break; } } stopnpctimer; announce "Current Time Taken : "+.Time/1000+"."+.Time%1000+" Seconds. ",bc_self,0xED1ADC; // removemapflag .Map$,mf_noskill; sleep2 5000; mapwarp .Map$,"prontera",156,175; end; } job3_arch01 mapflag nocommand 50 job3_arch01 mapflag gvg on job3_arch01 mapflag gvg_castle job3_arch01 mapflag monster_noteleport job3_arch01 mapflag nosave SavePoint im trying to figure out whats wrong but i cant #TIA
  7. Requesting a script for 1. assassin job only can enter inside the pvp room 2. only custom item will allowed to use inside the sinx pvp room thanks in advance! here's my script prt_ext,165,138,5 script PvP Arena 574,{ if(agitcheck()) goto nowoetime; mes "[PvP Battle Room]"; mes "Let's Go!!!!!"; menu "No limit [" + getmapusers("guild_vs3") + "]",pvp1, "Non Donate [" + getmapusers("guild_vs4") + "]",spvp, "Guild vs Guild [" + getmapusers("guild_vs2") + "]",gvg1; nowoetime: mes "[PvP Warper]"; mes "You cannot enter to PvP Room during WoE!"; close; pvp1: warp "guild_vs3",0,0; announce ""+ strcharinfo(0) +" Has Entered The PVP Room.",bc_all; close; gvg1: warp "guild_vs2",0,0; announce ""+ strcharinfo(0) +" Has Entered The GVG Room.",bc_all; close; spvp: if(countitem(59138) > 0 || countitem(59139) > 0 || countitem(59140) > 0 || countitem(59141) > 0 || countitem(59142) > 0 || countitem(59143) > 0 || countitem(59144) > 0 || countitem(59145) > 0 || countitem(59146) > 0 || countitem(59147) > 0 || countitem(59148) > 0 || countitem(59149) > 0 || countitem(59155) > 0 || countitem(59150) > 0 || countitem(59151) > 0 || countitem(59152) > 0 || countitem(59153) > 0 || countitem(59154) > 0 //donate weapon || countitem(59000) > 0 || countitem(59001) > 0 || countitem(59002) > 0 || countitem(59003) > 0 || countitem(59004) > 0 || countitem(59005) > 0 || countitem(59006) > 0 || countitem(59007) > 0 || countitem(59008) > 0 || countitem(59009) > 0 || countitem(59010) > 0 || countitem(59011) > 0 || countitem(59012) > 0 || countitem(59013) > 0 || countitem(59014) > 0 //Pointers || countitem(501) > 0) goto donator; warp "guild_vs4",0,0; announce ""+ strcharinfo(0) +" Has Entered The PVP Room Non Donate.",bc_all; close; donator: mes "You are a donator you are not allowed to this room"; close; //OnPCDieEvent: //set @Die,@Die + 1; //if( @Die % 2 == 0 ) warp "SavePoint",0,0; //end; } //Mapflag guild_vs4 mapflag pvp guild_vs4 mapflag nowarp guild_vs4 mapflag nowarpto guild_vs4 mapflag noreturn guild_vs4 mapflag nosave SavePoint guild_vs4 mapflag notrade guild_vs3 mapflag pvp guild_vs3 mapflag nowarp guild_vs3 mapflag nowarpto guild_vs3 mapflag noreturn guild_vs3 mapflag nosave SavePoint guild_vs3 mapflag noicewall guild_vs3 mapflag pvp_noparty guild_vs3 mapflag pvp_noguild guild_vs4 mapflag notrade guild_vs2 mapflag pvp guild_vs2 mapflag nowarp guild_vs2 mapflag nowarpto guild_vs2 mapflag noreturn guild_vs2 mapflag nosave SavePoint - script DOTAPVP -1,{ OnInit: // Config set .sound, 2; // soundeffect : 0 - disable, 1 - play soundeffect to all players on map, 2 - play soundeffect to an area around the killer, 3 - play soundeffect to killer only set .ownage, 2; // ownage announcement : 0 - disable, 1 - party owns, 2 - guild owns set .announce, 0; // make announce to : 0 - global, 1 - map set .announcemap, 1; // announce the map name in the announcement ? : 0 - off, 1 - on set .announcekill, 1; // announce who pawn who's head : 0 - off, 1- on set .msg_die, 0; // show message who kill you when die : 0 - off, 1- on set .msg_kill, 0; // show message you kill who when killed someone : 0 - off, 1- on set .gmnokill, 0; // GMs are not suppose to kill players. A GM with <this number> level or higher will do nothing. IF set to 60, GM60 and above kill any player will not get anything : 0 - off set .killingspree, 3; set .dominating, 4; set .megakill, 5; set .unstoppable, 6; set .wickedsick, 7; set .monsterkill, 8; set .godlike, 9; set .holyshit, 10; set .continue, 1; // after beyond-godlike, every <this number> kills will make announcement again set .owned, 5; // how many times the party/guild has to kill to announce ownage set .owncontinue, 1; // after ownage, every <this number> party/guild cumulative kills will make ownage announce again setarray .maptrigger$, // only these maps will trigger this script "all", // comment this line to only trigger this script on these listed maps "guild_vs1", "guild_vs2", "guild_vs3", "guild_vs4", "guild_vs5", "guild_vs2-1"; // anti-sit-killer system // a player must kill another player with this minimum <this number> level to get the announcement and in the ladder. // Otherwise only have streak ended announcement and killed player's streak reset. // Its possible for a level 1 novice to kill a level 55 player and he/she will still get in the ladder // but a level 55 kill a level 1 player will get nothing // 0 - off this system ( default is 55, pk setting ) set .lvltokill, 0; // when a player kill another same player <this number> times in a row, the player is warp back to save point. // and the player's streak and ownage count will deduct accordingly // 0 - off this system set .counttopunish, 0; // minimum level range to kill another player // eg. when set to 20, player level 99 needs to kill another player with minimum level of 79 to get announcement and increase the kill rank. // but a player with base level 50 kills a level 99 will also get the announcement // higher base level cannot kill lower level, but lower level can kill higher level // 0 - off this system set .minlvlrange, 0; // Config ends ------------------------------------------------------------------------------------------ // to prevent bug happen if ( .ownage < 0 || .ownage > 2 ) set .ownage, 0; if ( .announce < 0 || .announce > 1 ) set .announce,0; if ( .continue < 1 ) set .continue, 1; if ( .owncontinue < 1 ) set .owncontinue, 1; if ( .gmnokill <= 0 ) set .gmnokill, 100; if ( .lvltokill <= 1 ) set .lvltokill, 0; if ( .counttopunish <= 1 ) set .counttopunish, 0; set .maptriggersize, getarraysize(.maptrigger$); end; // script start OnPCKillEvent: if ( getgmlevel() >= .gmnokill ) end; getmapxy .@map$, .@x, .@y; if ( .maptrigger$ != "all" ) { for ( set .@i, 0; .@i < .maptriggersize; set .@i, .@i +1 ) { if ( .@map$ == .maptrigger$[.@i] ) break; } if ( .@i == .maptriggersize ) end; } attachrid killedrid; if ( killerrid != getcharid(3) && ( .msg_die || .msg_kill ) ) { if ( .msg_die ) message strcharinfo(0),"You have been killed by "+ rid2name(killerrid); if ( .msg_kill ) message rid2name(killerrid),"You just killed "+ strcharinfo(0); } if ( @PlayersKilledStreak >= .holyshit ) set .@streakname$,"Beyond Godlike"; else if ( @PlayersKilledStreak >= .godlike ) set .@streakname$,"Godlike"; else if ( @PlayersKilledStreak >= .monsterkill ) set .@streakname$,"Monster Kill"; else if ( @PlayersKilledStreak >= .wickedsick ) set .@streakname$,"Wicked Sick"; else if ( @PlayersKilledStreak >= .unstoppable ) set .@streakname$,"Unstoppable"; else if ( @PlayersKilledStreak >= .megakill ) set .@streakname$,"Mega-kill"; else if ( @PlayersKilledStreak >= .dominating ) set .@streakname$,"Dominating"; else if ( @PlayersKilledStreak >= .killingspree ) set .@streakname$,"Killing Spree"; if ( @PlayersKilledStreak >= .killingspree && killerrid == getcharid(3) ) announce strcharinfo(0) +" has ended "+( (sex)?"him":"her" )+" own "+ .@streakname$ +"["+ @PlayersKilledStreak +"] streak "+( (.announcemap)?("at "+ .@map$):""),16|.announce; else if ( @PlayersKilledStreak >= .killingspree ) announce rid2name(killerrid) +" has ended "+ strcharinfo(0) +"'s "+ .@streakname$ +"["+ @PlayersKilledStreak +"] streak "+( (.announcemap)?("at "+ .@map$):""),16|.announce; else if ( .announcekill && killerrid != getcharid(3) ) announce rid2name(killerrid) +" has pawned "+ strcharinfo(0) +"'s head "+( (.announcemap)?("at "+ .@map$):""),16|.announce; set @PlayersKilledStreak,0; set @dota_multikills,0; if ( .ownage && getcharid(.ownage) ) { setd ".dotaown_"+ getcharid(.ownage), 0; set .@killedgroup, getcharid(.ownage); } if ( killerrid == getcharid(3) || baselevel < .lvltokill ) end; if ( .minlvlrange ) set .@killedlvl, baselevel; attachrid killerrid; if ( .minlvlrange && .@killedlvl + .minlvlrange < baselevel ) end; if ( .counttopunish ) { if ( @sitkillminute != gettime(2) ) { deletearray @sitkillid, 128; deletearray @sitkilltimes, 128; set @sitkillminute, gettime(2); } set .@sitkillsize, getarraysize(@sitkillid); for ( set .@i,0; .@i < .@sitkillsize; set .@i, .@i +1 ) { if ( @sitkillid[.@i] != killedrid ) continue; else { set @sitkilltimes[.@i], @sitkilltimes[.@i] +1 ; if ( @sitkilltimes[.@i] >= .counttopunish ) { warp "SavePoint",0,0; announce strcharinfo(0) +" , Stop killing "+ rid2name(killedrid) + " !!!",0; debugmes strcharinfo(0) +" is sit-killing "+ rid2name(killedrid) +" for "+ @sitkilltimes[.@i] + " times"; logmes "is sit-killing "+ rid2name(killedrid) +" for "+ @sitkilltimes[.@i] +" times"; set @PlayersKilledStreak, @PlayersKilledStreak +1 - .counttopunish; set PlayersKilled, PlayersKilled +1 - .counttopunish; if ( .ownage && getcharid(.ownage) ) setd ".dotaown_"+ getcharid(.ownage), getd(".dotaown_"+ getcharid(.ownage) ) +1 - .counttopunish; end; } break; } } if ( .@i == .@sitkillsize ) { set @sitkillid[.@i], killedrid; set @sitkilltimes[.@i], 1; } } set @PlayersKilledStreak, @PlayersKilledStreak + 1; set PlayersKilled, PlayersKilled + 1; if ( @PlayersKilledStreak == .killingspree ) setarray .@streakname$,"killingspree.wav","is on a KILLING SPREE","!"; else if ( @PlayersKilledStreak == .dominating ) setarray .@streakname$,"dominating.wav","is DOMINATING","!"; else if ( @PlayersKilledStreak == .megakill ) setarray .@streakname$,"megakill.wav","has a MEGA KILL","!"; else if ( @PlayersKilledStreak == .unstoppable ) setarray .@streakname$,"unstoppable.wav","is UNSTOPPABLE","!!"; else if ( @PlayersKilledStreak == .wickedsick ) setarray .@streakname$,"wickedsick.wav","is WICKED SICK","!!"; else if ( @PlayersKilledStreak == .monsterkill ) setarray .@streakname$,"monsterkill.wav","has a MONSTER KILL","!!"; else if ( @PlayersKilledStreak == .godlike ) setarray .@streakname$,"godlike.wav","is GODLIKE","!!!"; else if ( @PlayersKilledStreak >= .holyshit && ( (@PlayersKilledStreak - .holyshit) % .continue == 0 ) ) setarray .@streakname$,"triplekill.wav","is BEYOND GODLIKE",". Someone KILL "+( (sex)?"HIM":"HER" ) +"!!!!!!"; if ( .@streakname$[1] != "" ) { announce strcharinfo(0) +" "+ .@streakname$[1] +"["+ @PlayersKilledStreak +"] "+( (.announcemap)?("at "+ .@map$):"") + .@streakname$[2],16|.announce; if ( .sound == 1 ) soundeffectall .@streakname$[0],0,.@map$; else if ( .sound == 2 ) soundeffectall .@streakname$[0],0; else if ( .sound == 3 ) soundeffect .@streakname$[0],0; } set @dota_multikills, @dota_multikills + 1; deltimer "DOTAPVP::OnStreakReset"; addtimer 18000,"DOTAPVP::OnStreakReset"; if ( .ownage ) { set .@sideid, getcharid(.ownage); if ( .@sideid != .@killedgroup ) setd ".dotaown_"+ .@sideid, getd(".dotaown_"+ .@sideid ) + 1; } set .@dota_multikills, @dota_multikills; set .@origin, getcharid(3); sleep 1500; if ( .@sideid && .ownage && .@sideid != .@killedgroup && getd(".dotaown_"+ .@sideid) >= .owned && ( ( getd(".dotaown_"+ .@sideid) - .owned ) % .owncontinue == 0 ) ) { if ( .announce ) mapannounce .@map$, "The "+( (.ownage == 1)?"party":"guild" )+" ["+( (.ownage == 1)?getpartyname(.@sideid):getguildname(.@sideid) )+"] is OWNING["+ getd(".dotaown_"+ .@sideid) +"] !!!",16; else announce "The "+( (.ownage == 1)?"party":"guild" )+" ["+( (.ownage == 1)?getpartyname(.@sideid):getguildname(.@sideid) )+"] is OWNING["+ getd(".dotaown_"+ .@sideid) +"] !!!",16; if ( .sound == 1 ) soundeffectall "ownage.wav",0,.@map$; else if ( .sound == 2 ) soundeffectall "ownage.wav",0; else if ( .sound == 3 && attachrid(.@origin) ) soundeffect "ownage.wav",0; } sleep 1250; if ( !attachrid(.@origin) ) end; if ( .@dota_multikills == 2 ) { if ( .announce ) mapannounce .@map$, strcharinfo(0) +" just got a Double Kill !",16; else announce strcharinfo(0) +" just got a Double Kill !",16; if ( .sound == 1 ) soundeffectall "doublekill.wav",0,.@map$; else if ( .sound == 2 ) soundeffectall "doublekill.wav",0; else if ( .sound == 3 ) soundeffect "doublekill.wav",0; } else if ( .@dota_multikills == 3 ) { if ( .announce ) mapannounce .@map$, strcharinfo(0) +" just got a Triple Kill !!!",16; else announce strcharinfo(0) +" just got a Triple Kill !!!",16; if ( .sound == 1 ) soundeffectall "triplekill.wav",0,.@map$; else if ( .sound == 2 ) soundeffectall "triplekill.wav",0; else if ( .sound == 3 ) soundeffect "triplekill.wav",0; } else if ( .@dota_multikills == 4 ) { if ( .announce ) mapannounce .@map$, strcharinfo(0) +" just got a Ultra Kill !!!",16; else announce strcharinfo(0) +" just got a Ultra Kill !!!",16; if ( .sound == 1 ) soundeffectall "ultrakill.wav",0,.@map$; else if ( .sound == 2 ) soundeffectall "ultrakill.wav",0; else if ( .sound == 3 ) soundeffect "ultrakill.wav",0; } else if ( .@dota_multikills >= 5 ) { if ( .announce ) mapannounce .@map$, strcharinfo(0) +" is on a Rampage !!!",16; else announce strcharinfo(0) +" is on a Rampage !!!",16; if ( .sound == 1 ) soundeffectall "killingspree.wav",0,.@map$; else if ( .sound == 2 ) soundeffectall "killingspree.wav",0; else if ( .sound == 3 ) soundeffect "killingspree.wav",0; } end; OnWhisperGlobal: dispbottom "Your current Streak : "+ @PlayersKilledStreak; dispbottom "Your total Kills : "+ PlayersKilled; if ( .ownage && getcharid(.ownage) ) dispbottom "Your "+( (.ownage ==1)?"party":"guild" )+" Own : "+ getd(".dotaown_"+ getcharid(.ownage) ); end; OnStreakReset: set @dota_multikills, 0; end; } //- script Unfro113 -1,{ //OnPCStatCalcEvent: //if(isequipped(4302)) { //bonus2 bSubRace,RC_Player,12; //end; //} //} //- script Unfro113 -1,{ //OnPCStatCalcEvent: //if(isequipped(60166)) { //if(BaseClass==Job_Taekwon) bonus bstr,5; //end; //} //}
  8. getmapxy and getmonsterinfo now use constants. Find: getmapxy .@map$, .@x, .@y, 0; Replace: getmapxy .@map$, .@x, .@y; Find: getmapxy .@map$, .@x, .@y ,1; Replace: getmapxy .@map$, .@x, .@y ,BL_NPC; Find all: getmonsterinfo( ..., 0) Replace: getmonsterinfo( ..., MOB_NAME) // ....... if your server has { Overwriting user function [int__] } don't blame me .......... function script int__ { set .@num, atoi(getarg(0)+""); if ( .@num == 0 || .@num >= 2147483647 ) return getarg(0); set .@l, getstrlen(.@num+""); for ( set .@i,0; .@i < .@l; set .@i, .@i + 1 ) { set .@num$, .@num % pow(10,.@i+1) / pow(10,.@i) + .@num$; if ( (.@i+1) % 3 == 0 && .@i+1 != .@l ) set .@num$, ","+ .@num$; } return .@num$; } //===== eAthena Script ====================================== //= Private MVP/Branch Room //===== By: =============================================== //= by ~AnnieRuru~ //===== Current Version: ====================================== //= 1.4a //===== Compatible With: ===================================== //= rathena 16819 //===== Description: ========================================= //= Player can rent MVP room for the player him/herself, for party or for guilds //===== Topic ================================================= //= http://www.eathena.ws/board/index.php?showtopic=187654 //===== Additional Comments: ================================== //= 1.0 //= ---- break the tradition which a script only for a player, or only for a party. //= now 1 room can be use for party and another room can use for guilds. //= ---- timeout feature to prevent player owns the room indefinitely, //= by create a new account and sit/@at'ing inside overnight. //= ---- can disable mvp/boss summon via configuration and becomes a branch room script. //= ---- a double check to prevent players rent all the rooms for himself. //= 1.0a //= ---- fix a critial bug that the time count too fast -_-" //= 1.1 //= ---- added item cost to rent or to summon //= ---- added a config to limit summoning per session //= ---- added flood control option //= 1.2 //= ---- rewrite the waitingroom counter //= ---- optimize the script in a way can add custom summon group //= ---- add config to kill the monsters if the room just being left empty //= ---- add GM can kick room in use //= ---- add able to spawn in numbers //= ---- add limitspawn can configure to negative to limit spawn in that group instead of individual one //= 1.3 //= ---- fix chatroom countdown issue due to rev13269 //= ---- fix a bug if 2 people rent a room at same time, the later 1 will get the room //= ---- add a feature so the GM can know how long the room has rented or abandoned //= 1.4 //= ---- update with new mvp and mini bosses //= ---- fix an exploit if server allow to use @mail, player can send item/zeny away to prevent item/zeny deletion when registering the room //= ---- players die inside mvp room shouldn't lose exp //= 1.4a //= ---- fix this to use in rathena //======================================================== // This is the shop for this Branch room IF you already enable it. Can sell whatever things you want. - shop MVP room#branch -1,604:100000,12103:1000000 - script MVP Summoner -1,{ goto L_Start; OnInit: getmapxy .@map$, .@x, .@y, BL_NPC; if ( .@map$ == "" ) { // Config --------------------------------------------------------------------------------------- // Time for rent a room IN MINUTES. When time out, players inside the room will kick out. Do Not set this as 0 set .timeout, 30; // if the room left empty for # minutes, will be treated as give up the room. Do Not set this as 0 set .nobodygiveup, 2; // NOTE : The script only search item OR zeny. if you specify item amount, then it will ask for the item. If item amount is 0, then it will ask for zeny. // the cost to rent a room set .rentitemid, 674; // item id use for rent a room - 674 - mithil coin set .rentitemamount, 0; // amount of items to rent a room set .rentcost, 1000000; // otherwise, zeny cost to rent a room // limit each room can only summon 1 monster at a time. (only the Summoning option) // Turn it off (0) means the player can summon a lot of monsters as long as the player has enough zeny/item. High rate server players love the room with a lot MVPs // Turn it on (1) means the player have to kill existing monster before can summon a new one. Low rate server player prefer to take out MVP 1 by 1 set .floodcontrol, 1; // if .floodcontrol is turn off, your players might experience lag if they summoned too many MVPs // so what is the maximum input to limit your players summon too many ? set .inputlimit, 30; // If the room has left over monsters while nobody in the room and the room not give up yet, shall we kill monsters in empty room ? set .killmonster, 1; // Default is yes // Options menu setting for MVP Summoner NPC. set .@menu[0], 1; // Turn Heal option On/Off set .@menu[1], 1; // Turn Group 1 summons On/Off -> MVP set .@menu[2], 1; // Turn Group 2 summons On/Off -> mini boss set .@menu[3], 0; // Turn Group 3 summons On/Off set .@menu[4], 0; // Turn Group 4 summons On/Off set .@menu[5], 0; // Turn Group 5 summons On/Off set .@menu[6], 0; // Turn Group 6 summons On/Off set .@menu[7], 0; // Turn Group 7 summons On/Off set .@menu[8], 0; // Turn Group 8 summons On/Off set .@menu[9], 0; // Turn Group 9 summons On/Off set .@menu[10], 0; // Sell shop items options On/Off ( shop npc above ) // set respawn point when they leave the room. Obviously warp to the Private MVP Room Warper npc set .respawnmap$, "prontera"; // Note : "SavePoint" does NOT work set .respawnx, 150; set .respawny, 174; // The minimum GM level can kick a room in use set .gmlvlkick, 80; // .limitspawn in previous revision changed to .grouplimit . // it is for limit each monster spawn per session, prevent them only killing same monster again and again // Now you can configure one group has limited summon, and another group has unlimited summon // Tips: if you server has an insane custom MVP, you can put your custom mob to Group 3~9 with insane item cost, and limit only 1 summon per session // .grouplimit use amount, means if group1limit set to 10, then each session can only summon up to 10 amount of that kind of monster. 0 is unlimited // --------- // Group 1 -> MVP // --------- set .group1name$, "MVP"; // Group 1 name set .group1itemid, 674; // item id use for summon any Group 1 monster - 674 - mithil coin set .group1itemamount, 0; // amount of items to summon a Group 1 monster set .group1cost, 100000; // if no item is specify, zeny cost to summon a Group 1 monster set .group1limit, 0; // limit of summon of Group 1 monster per session, prevent them only killing same monster again and again setarray .group1id, 1511,// Amon Ra 1647,// Assassin Cross Eremes 1785,// Atroce 1630,// Bacsojin 1039,// Baphomet 1874,// Beelzebub 1272,// Dark Lord 1719,// Datale 1046,// Doppelgangger 1389,// Dracula 1112,// Drake 1115,// Eddga 1418,// Evil Snake Lord 1871,// Fallen Bishop 1252,// Garm 1768,// Gloom Under Night 1086,// Golden Thief Bug 1885,// Gopinich 1649,// High Priest Magaleta 1651,// High Wizard Katrinn 1832,// Ifrit 1492,// Incantation Samurai 1734,// Kiel D-01 1251,// Knight of Windstorm 1779,// Ktullanux // 1980,// Kubkin ( I think this mvp is still new ) 1688,// Lady Tanee 1646,// Lord Knight Seyren 1373,// Lord of Death 1147,// Maya 1059,// Mistress 1150,// Moonlight Flower 1087,// Orc Hero 1190,// Orc Lord 1038,// Osiris 1157,// Pharaoh 1159,// Phreeoni 1623,// RSX 0806 1650,// Sniper Shecil 1583,// Tao Gunka 1708,// Thanatos 1312,// Turtle General 1751,// Valkyrie Randgris 1685,// Vesper 1648,// Whitesmith Harword 1917,// Wounded Morroc 1658;// Ygnizem // --------- // Group 2 -> mini boss // --------- set .group2name$, "mini boss"; // Group 2 name set .group2itemid, 674; // item id use for summon any Group 2 monster - 674 - mithil coin set .group2itemamount, 0; // amount of items to summon a Group 2 monster set .group2cost, 10000; // if no item is specify, zeny cost to summon a Group 2 monster set .group2limit, 0; // limit of summon of Group 2 monster per session, prevent them only killing same monster again and again setarray .group2id, 1096,// Angeling 1388,// Archangeling 1795,// Bloody Knight 1830,// Bow Guardian 1839,// Byorgue 1309,// Cat O' Nine Tail 1283,// Chimera 1302,// Dark Illusion 1198,// Dark Priest 1582,// Deviling 1091,// Dragon Fly 1093,// Eclipse 1205,// Executioner 1783,// Galion 1592,// Gangster 1120,// Ghostring 1259,// Gryphon 1720,// Hydro 1090,// Mastering 1289,// Maya Purple 1262,// Mutant Dragon 1203,// Mysteltainn 1870,// Necromancer 1295,// Owl Baron 1829,// Sword Guardian 1204,// Tirfing 1089,// Toad 1092,// Vagabond Wolf 1765;// Valkyrie // --------- // Group 3 // --------- set .group3name$, "Poring-Family"; // Group 3 name set .group3itemid, 12109; // item id use for summon any Group 3 monster - 12109 - Poring box set .group3itemamount, 1; // amount of items to summon a Group 3 monster set .group3cost, 0; // if no item is specify, zeny cost to summon a Group 3 monster set .group3limit, -5; // limit of summon of Group 3 monster per session, prevent them only killing same monster again and again setarray .group3id, 1002,// Poring 1113,// Drops 1031,// Poporing 1242,// Marin 1062,// Santa Poring 1613,// Metaling 1784,// Stapo 1090,// Mastering 1096,// Angeling 1120,// Ghostring 1582,// Deviling 1388,// Arc Angeling 1502;// Pori Pori // --------- // Group 4 // --------- set .group4name$, ""; // Group 4 name set .group4itemid, 0; // item id use for summon any Group 4 monster set .group4itemamount, 0; // amount of items to summon a Group 4 monster set .group4cost, 0; // if no item is specify, zeny cost to summon a Group 4 monster set .group4limit, 0; // limit of summon of Group 4 monster per session, prevent them only killing same monster again and again setarray .group4id, 1001, 1002; // --------- // Group 5 // --------- set .group5name$, ""; // Group 5 name set .group5itemid, 0; // item id use for summon any Group 5 monster set .group5itemamount, 0; // amount of items to summon a Group 5 monster set .group5cost, 0; // if no item is specify, zeny cost to summon a Group 5 monster set .group5limit, 0; // limit of summon of Group 5 monster per session, prevent them only killing same monster again and again setarray .group5id, 1001, 1002; // --------- // Group 6 // --------- set .group6name$, ""; // Group 6 name set .group6itemid, 0; // item id use for summon any Group 6 monster set .group6itemamount, 0; // amount of items to summon a Group 6 monster set .group6cost, 0; // if no item is specify, zeny cost to summon a Group 6 monster set .group6limit, 0; // limit of summon of Group 6 monster per session, prevent them only killing same monster again and again setarray .group6id, 1001, 1002; // --------- // Group 7 // --------- set .group7name$, ""; // Group 7 name set .group7itemid, 0; // item id use for summon any Group 7 monster set .group7itemamount, 0; // amount of items to summon a Group 7 monster set .group7cost, 0; // if no item is specify, zeny cost to summon a Group 7 monster set .group7limit, 0; // limit of summon of Group 7 monster per session, prevent them only killing same monster again and again setarray .group7id, 1001, 1002; // --------- // Group 8 // --------- set .group8name$, ""; // Group 8 name set .group8itemid, 0; // item id use for summon any Group 8 monster set .group8itemamount, 0; // amount of items to summon a Group 8 monster set .group8cost, 0; // if no item is specify, zeny cost to summon a Group 8 monster set .group8limit, 0; // limit of summon of Group 8 monster per session, prevent them only killing same monster again and again setarray .group8id, 1001, 1002; // --------- // Group 9 // --------- set .group9name$, ""; // Group 9 name set .group9itemid, 0; // item id use for summon any Group 9 monster set .group9itemamount, 0; // amount of items to summon a Group 9 monster set .group9cost, 0; // if no item is specify, zeny cost to summon a Group 9 monster set .group9limit, 0; // limit of summon of Group 9 monster per session, prevent them only killing same monster again and again setarray .group9id, 1001, 1002; // Config Ends ------------------------------------------------------------------------ if ( .timeout == 0 ) set .timeout, 60; if ( .nobodygiveup == 0 ) set .nobodygiveup, 5; if ( .inputlimit < 1 ) set .inputlimit, 1; if ( .rentitemid && .rentitemamount ) { if ( getitemname(.rentitemid) == "null" ) { debugmes "Private MVP Room: Rent a room is using invalid item id."; } } set .@i, 1; while ( .@i <= 9 ) { if ( .@menu[.@i] && getd(".group"+ .@i +"itemid") && getd(".group"+ .@i +"itemamount") ) { if ( getitemname( getd(".group"+ .@i +"itemid") ) == "null" ) { debugmes "Private MVP Room: Group no. "+ .@i +" is using invalid item id."; } } set .@i, .@i +1 ; } set .menu$, ( (.@menu[0])?"Heal":"" )+":"+( (.@menu[1])?"Summon "+ .group1name$:"" )+":"+( (.@menu[2])?"Summon "+ .group2name$:"" )+":"+( (.@menu[3])?"Summon "+ .group3name$:"" )+":"+( (.@menu[4])?"Summon "+ .group4name$:"" )+":"+( (.@menu[5])?"Summon "+ .group5name$:"" )+":"+( (.@menu[6])?"Summon "+ .group6name$:"" )+":"+( (.@menu[7])?"Summon "+ .group7name$:"" )+":"+( (.@menu[8])?"Summon "+ .group8name$:"" )+":"+( (.@menu[9])?"Summon "+ .group9name$:"" )+":"+( (.@menu[10])?"Buy branches":"" )+":Leave this room:Give up this room"; set .@i, 1; while ( .@i <= 9 ) { setd ".group"+ .@i +"idsize", getarraysize( getd(".group"+ .@i +"id") ); if ( .@menu[.@i] && getd(".group"+ .@i +"limit") <= 0 ) { set .@j, 0; while ( .@j < getd(".group"+ .@i +"idsize") ) { setd ".group"+ .@i +"menu$", getd(".group"+ .@i +"menu$") + getmonsterinfo( getd(".group"+ .@i +"id["+ .@j +"]"), MOB_NAME) +":"; set .@j, .@j +1 ; } } set .@i, .@i +1 ; } } else { sleep 1; mapannounce .@map$, "Admin has refresh the server, please register the room again.", 1; mapwarp .@map$, .respawnmap$, .respawnx, .respawny; } end; L_Start: // I hate gotos ... but ... set .@dif, strnpcinfo(2); if ( .remind[.@dif] == 0 ) { set .remind[.@dif], 1; initnpctimer; } mes "[MVP Summoner]"; mes "Hi, what can I do for you ?"; next; switch ( select(.menu$) ) { case 1: mes "[MVP Summoner]"; if ( mobcount("this","") > 0 ) { mes "I cannot offer heal service when there are monsters around."; close; } sc_end sc_stone; sc_end sc_slowdown; sc_end sc_freeze; sc_end sc_sleep; sc_end sc_curse; sc_end sc_silence; sc_end sc_confusion; sc_end sc_blind; sc_end sc_bleeding; sc_end sc_decreaseagi; sc_end sc_poison; sc_end sc_hallucination; sc_end sc_stripweapon; sc_end sc_striparmor; sc_end sc_striphelm; sc_end sc_stripshield; sc_end sc_changeundead; sc_end sc_orcish; sc_end sc_berserk; sc_end sc_ske; sc_end sc_swoo; sc_end sc_ska; percentheal 100,100; specialeffect2 7; mes "You have completely healed."; close; default: set .@group, @menu -1; if ( .floodcontrol && mobcount("this","") > 0 ) { mes "[MVP Summoner]"; mes "I cannot summon another monster when there are monsters around."; close; } else if ( getd(".group"+ .@group +"itemid") && getd(".group"+ .@group +"itemamount") ) { mes "[MVP Summoner]"; mes "The cost to summon a "+ getd(".group"+ .@group +"name$") +" is "+ getd(".group"+ .@group +"itemamount") +" "+ getitemname( getd(".group"+ .@group +"itemid") ) +"."; if ( getd(".group"+ .@group +"limit") < 0 ) mes "("+( ( ~getd(".group"+ .@group +"limit")+1 - getd(".group"+ .@group +"limit"+ .@dif) <= 0 )?0:( ~getd(".group"+ .@group +"limit")+1 - getd(".group"+ .@group +"limit"+ .@dif) ) )+") more summons for this group."; next; } else if ( getd(".group"+ .@group +"cost") ) { mes "[MVP Summoner]"; mes "The cost to summon a "+ getd(".group"+ .@group +"name$") +" is "+ callfunc("int__", getd(".group"+ .@group +"cost") ) +" zeny."; if ( getd(".group"+ .@group +"limit") < 0 ) mes "("+( ( ~getd(".group"+ .@group +"limit")+1 - getd(".group"+ .@group +"limit"+ .@dif) <= 0 )?0:( ~getd(".group"+ .@group +"limit")+1 - getd(".group"+ .@group +"limit"+ .@dif) ) )+") more summons for this group."; next; } else if ( getd(".group"+ .@group +"limit") < 0 ) { mes "[MVP Summoner]"; mes "("+( ( ~getd(".group"+ .@group +"limit")+1 - getd(".group"+ .@group +"limit"+ .@dif) <= 0 )?0:( ~getd(".group"+ .@group +"limit")+1 - getd(".group"+ .@group +"limit"+ .@dif) ) )+") more summons for this group."; next; } if ( getd(".group"+ .@group +"limit") < 0 && getd(".group"+ .@group +"limit"+ .@dif) >= ~getd(".group"+ .@group +"limit")+1 ) { mes "[MVP Summoner]"; mes "I'm sorry, but you can't summon any more monster for this group."; close; } else if ( getd(".group"+ .@group +"limit") > 0 ) { for ( set .@i, 0; .@i < getd(".group"+ .@group +"idsize"); set .@i, .@i +1 ) set .@menu$, .@menu$ +( ( getd(".group"+ .@group +"limit"+ .@dif +"["+ .@i +"]") >= getd(".group"+ .@group +"limit") )?"^999999":"^000000" )+ getmonsterinfo( getd(".group"+ .@group +"id["+ .@i +"]"), MOB_NAME) +" ("+ ( ( getd(".group"+ .@group +"limit") - getd(".group"+ .@group +"limit"+ .@dif +"["+ .@i +"]") <= 0 )?0:( getd(".group"+ .@group +"limit") - getd(".group"+ .@group +"limit"+ .@dif +"["+ .@i +"]") ) ) +")"+":"; set .@menu, select(.@menu$) -1; } else set .@menu, select( getd(".group"+ .@group +"menu$") ) -1; mes "[MVP Summoner]"; if ( .floodcontrol == 0 && .inputlimit > 1 ) { mes "Input an amount of monsters to summon."; next; input .@amount; if ( .@amount == 0 ) close; else if ( .@amount > .inputlimit ) set .@amount, .inputlimit; mes "[MVP Summoner]"; } else set .@amount, 1; if ( getd(".group"+ .@group +"itemid") && getd(".group"+ .@group +"itemamount") ) { if ( countitem( getd(".group"+ .@group +"itemid") ) < getd(".group"+ .@group +"itemamount") * .@amount ) { mes "You don't have enough "+ getitemname( getd(".group"+ .@group +"itemid") ) +" to summon a "+ getd(".group"+ .@group +"name$") +"."; close; } } else if ( getd(".group"+ .@group +"cost") ) { if ( zeny < getd(".group"+ .@group +"cost") * .@amount ) { mes "You don't have enough zeny to summon a "+ getd(".group"+ .@group +"name$") +"."; close; } } if ( .floodcontrol && mobcount("this","") > 0 ) { mes "I cannot summon another monster when there are monsters around."; close; } else if ( getd(".group"+ .@group +"limit") > 0 ) { if ( getd(".group"+ .@group +"limit"+ .@dif +"["+ .@menu +"]") >= getd(".group"+ .@group +"limit") ) { mes "I'm sorry, but you already summoned that monster too much. Try summon another."; close; } else if ( getd(".group"+ .@group +"limit"+ .@dif +"["+ .@menu +"]") + .@amount > getd(".group"+ .@group +"limit") ) { mes "The amount you input is more than the limit you can summon. Try reduce the amount."; close; } } else if ( getd(".group"+ .@group +"limit") < 0 ) { if ( getd(".group"+ .@group +"limit"+ .@dif) >= ~getd(".group"+ .@group +"limit")+1 ) { mes "I'm sorry, but you can't summon any more monster for this group."; close; } else if ( getd(".group"+ .@group +"limit"+ .@dif) + .@amount > ~getd(".group"+ .@group +"limit")+1 ) { mes "The amount you input is more than the limit you can summon. Try reduce the amount."; close; } } mes "Summoning "+ .@amount +" "+ getmonsterinfo( getd(".group"+ .@group +"id["+ .@menu +"]"), MOB_NAME) +"."; mes "Ok, get ready ?"; close2; if ( .floodcontrol && mobcount("this","") > 0 ) end; if ( getd(".group"+ .@group +"itemid") && getd(".group"+ .@group +"itemamount") ) { if ( countitem( getd(".group"+ .@group +"itemid") ) < getd(".group"+ .@group +"itemamount") * .@amount ) end; delitem getd(".group"+ .@group +"itemid"), getd(".group"+ .@group +"itemamount") * .@amount; } else if ( getd(".group"+ .@group +"cost") ) { if ( zeny < getd(".group"+ .@group +"cost") * .@amount ) end; set zeny, zeny - getd(".group"+ .@group +"cost") * .@amount; } if ( getd(".group"+ .@group +"limit") > 0 ) { if ( getd(".group"+ .@group +"limit"+ .@dif +"["+ .@menu +"]") + .@amount > getd(".group"+ .@group +"limit") ) end; setd ".group"+ .@group +"limit"+ .@dif +"["+ .@menu +"]", getd(".group"+ .@group +"limit"+ .@dif +"["+ .@menu +"]") + .@amount; } else if ( getd(".group"+ .@group +"limit") < 0 ) { if ( getd(".group"+ .@group +"limit"+ .@dif) + .@amount > ~getd(".group"+ .@group +"limit")+1 ) end; setd ".group"+ .@group +"limit"+ .@dif, getd(".group"+ .@group +"limit"+ .@dif) + .@amount; } monster "this", 0, 0, "--ja--", getd(".group"+ .@group +"id["+ .@menu +"]"), .@amount; end; case 11: if ( mobcount("this","") > 0 ) { mes "[MVP Summoner]"; mes "I cannot offer this service when there are monsters around."; close; } close2; callshop "MVP room#branch", 0; end; case 12: mes "[MVP Summoner]"; mes "Are you sure you want to leave this room ?"; mes "If this room left empty for more than "+ .nobodygiveup +" minutes, you lost ownership for this room."; if ( select( "Yes:No") == 2 ) close; warp .respawnmap$, .respawnx, .respawny; end; case 13: mes "[MVP Summoner]"; getmapxy .@map$, .@x, .@y; if ( getmapusers(.@map$) > 1 ) { mes "There are still some players in this room. Make sure you are the last member in this room to use this option."; close; } mes "Are you sure you want to give up this room ?"; if ( .rentcost ) mes "You will need to pay again to enter this room."; next; if ( select( "Yes:No" ) == 2 ) close; warp .respawnmap$, .respawnx, .respawny; set .remaintime[.@dif], -1; end; } close; OnEnterMap: set .@dif, strnpcinfo(2); set .remind[.@dif], 0; for ( set .@i, 1; .@i <= 9; set .@i, .@i +1 ) deletearray getd(".group"+ .@i +"limit"+ .@dif), getd(".group"+ .@i +"idsize"); set .nobodycounter[.@dif], 0; getmapxy .@map$, .@x, .@y ,BL_NPC; set .starttime[.@dif], gettimetick(2); do { set .remaintime[.@dif], .timeout * 60 + .starttime[.@dif] - gettimetick(2); set .@hour[.@dif], .remainTime[.@dif] / 3600 ; set .@min[.@dif], .remainTime[.@dif] % 3600 / 60 ; set .@sec[.@dif], .remainTime[.@dif] % 3600 % 60 ; delwaitingroom strnpcinfo(0); waitingroom "Time Left = "+( ( .@hour[.@dif] )?( .@hour[.@dif] +":"):"" )+( ( .@min[.@dif] < 10 )?"0"+ .@min[.@dif]: .@min[.@dif] )+":"+( ( .@sec[.@dif] < 10 )?"0"+ .@sec[.@dif]: .@sec[.@dif] ), 0; if ( getmapusers(.@map$) ) set .nobodycounter[.@dif], 0; else { set .nobodycounter[.@dif], .nobodycounter[.@dif] +1 ; if ( .nobodycounter[.@dif] > .nobodygiveup * 60 ) break; } sleep 995; } while ( .remaintime[.@dif] > 1 ); set .remaintime[.@dif], 0; delwaitingroom "MVP Summoner#"+ .@dif; mapwarp .@map$, .respawnmap$, .respawnx, .respawny; end; OnTimer100: stopnpctimer; npctalk "Hi ~ the bubble above my head is the countdown for using this room."; sleep 2000; npctalk "Sometimes, I can skip for about 1 second in the countdown."; sleep 3000; npctalk "That is because the server is experiencing minor lag problem."; sleep 3000; npctalk "So, don't complain about me cheated for the countdown ~ ^.^"; sleep 3000; npctalk "Have a nice day ~"; end; } prontera,148,174,5 script Private MVP Room 100,{ mes "[Private MVP Room]"; mes "Please select a private MVP room."; if ( getvariableofnpc(.rentitemid, "MVP Summoner") && getvariableofnpc(.rentitemamount, "MVP Summoner") ) mes "The cost to rent a room for "+ getvariableofnpc(.timeout, "MVP Summoner") +" minutes is "+ getvariableofnpc(.rentitemamount, "MVP Summoner") +" "+ getitemname( getvariableofnpc(.rentitemid, "MVP Summoner") ) +"."; else if ( getvariableofnpc(.rentcost, "MVP Summoner") ) mes "The cost to rent a room for "+ getvariableofnpc(.timeout, "MVP Summoner") +" minutes is "+ callfunc("int__", getvariableofnpc(.rentcost, "MVP Summoner") ) +" zeny."; else mes "You can only use the room for only "+ getvariableofnpc(.timeout, "MVP Summoner") +" minutes."; mes " "; for ( set .@i, 1; .@i <= 8; set .@i, .@i +1 ) { if ( getvariableofnpc(.remaintime[.@i],"MVP Summoner") ) { switch ( .type[.@i] ) { case 1: set .@color$, "^EE8800"; break; case 2: set .@color$, "^70CC11"; break; case 3: set .@color$, "^0000FF"; break; default: set .@color$, "^000000"; } mes "Room #"+ .@i +" = "+ .@color$ + .whoinuse$[.@i] +"^000000"; } } next; set .@room, select("MVP Room 1 ["+ getmapusers("06guild_01") +"]", "MVP Room 2 ["+ getmapusers("06guild_02") +"]", "MVP Room 3 ["+ getmapusers("06guild_03") +"]", "MVP Room 4 ["+ getmapusers("06guild_04") +"]", "MVP Room 5 ["+ getmapusers("06guild_05") +"]", "MVP Room 6 ["+ getmapusers("06guild_06") +"]", "MVP Room 7 ["+ getmapusers("06guild_07") +"]", "MVP Room 8 ["+ getmapusers("06guild_08") +"]"); if ( getvariableofnpc(.remaintime[.@room],"MVP Summoner") ) { if ( .inuseid[.@room] == getcharid(.type[.@room]) ) { if ( getvariableofnpc(.killmonster,"MVP Summoner") && getmapusers("06guild_0"+ .@room) == 0 ) killmonsterall "06guild_0"+ .@room; warp "06guild_0"+ .@room, 0,0; end; } else { mes "[Private MVP Room]"; switch ( .type[.@room] ) { case 1: set .@color$, "^EE8800Party "; break; case 2: set .@color$, "^70CC11Guild "; break; case 3: set .@color$, "^0000FFPlayer "; } mes "This room is reserved for "; mes .@color$ + .whoinuse$[.@room] +"^000000 ."; if ( getgmlevel() < getvariableofnpc(.gmlvlkick,"MVP Summoner") ) { mes "Please select another."; close; } mes " "; mes "Currently there are "+ getmapusers("06guild_0"+ .@room) +" players"; mes "in that room."; set .@remaintime, getvariableofnpc(.remaintime[.@room],"MVP Summoner"); mes "It still has "+( .@remaintime /60 )+"mn "+( .@remaintime %60 )+"s left."; set .@nobodycounter, getvariableofnpc(.nobodycounter[.@room],"MVP Summoner"); if ( .@nobodycounter ) mes "And have left empty for "+( .@nobodycounter /60 )+"mn "+( .@nobodycounter %60 )+"s."; mes "Kick them ?"; next; if ( select ( "No:Yes" ) == 1 ) close; set getvariableofnpc(.remaintime[.@room],"MVP Summoner"), -1; mes "[Private MVP Room]"; mes "Room#"+ .@room +" is empty now."; close; } } mes "[Private MVP Room]"; if ( getvariableofnpc(.rentitemid, "MVP Summoner") && getvariableofnpc(.rentitemamount, "MVP Summoner") ) { if ( countitem(getvariableofnpc(.rentitemid, "MVP Summoner")) < getvariableofnpc(.rentitemamount, "MVP Summoner") ) { mes "You don't have enough "+ getitemname( getvariableofnpc(.rentitemid, "MVP Summoner") ) +" to rent a room."; close; } } else if ( getvariableofnpc(.rentcost, "MVP Summoner") ) { if ( zeny < getvariableofnpc(.rentcost, "MVP Summoner") ) { mes "You don't have enough zeny to rent a room."; close; } } mes "You reserve this room for ..."; next; set .@type, select("For my party members", "For my guild members", "For personal account use" ); if ( getcharid(.@type) == 0 ) { mes "[Private MVP Room]"; mes "You do not own a "+( (.@type == 1)?"Party":"Guild" )+"."; close; } else if ( getvariableofnpc(.rentitemid, "MVP Summoner") && getvariableofnpc(.rentitemamount, "MVP Summoner") ) { if ( countitem(getvariableofnpc(.rentitemid, "MVP Summoner")) < getvariableofnpc(.rentitemamount, "MVP Summoner") ) { mes "You don't have enough "+ getitemname( getvariableofnpc(.rentitemid, "MVP Summoner") ) +" to rent a room."; close; } } else if ( getvariableofnpc(.remaintime[.@room],"MVP Summoner") ) { mes "[Private MVP Room]"; mes "I'm sorry, somebody else has already register this room faster than you."; close; } for ( set .@i, 1; .@i <= 8; set .@i, .@i +1 ) { if ( getvariableofnpc(.remaintime[.@i],"MVP Summoner") && .@type == .type[.@i] && getcharid(.@type) == .inuseid[.@i] ) { mes "[Private MVP Room]"; mes "You already rented Room#"+ .@i +". Use that room instead."; close; } } set .type[.@room], .@type; set .inuseid[.@room], getcharid(.@type); set .whoinuse$[.@room], strcharinfo( (.@type == 3)?0:.@type ); if ( getvariableofnpc(.rentitemid, "MVP Summoner") && getvariableofnpc(.rentitemamount, "MVP Summoner") ) { if ( countitem(getvariableofnpc(.rentitemid, "MVP Summoner")) < getvariableofnpc(.rentitemamount, "MVP Summoner") ) end; delitem getvariableofnpc(.rentitemid, "MVP Summoner"), getvariableofnpc(.rentitemamount, "MVP Summoner"); } else if ( getvariableofnpc(.rentcost, "MVP Summoner") ) { if ( zeny < getvariableofnpc(.rentcost, "MVP Summoner") ) end; set zeny, zeny - getvariableofnpc(.rentcost, "MVP Summoner"); } warp "06guild_0"+ .@room, 0,0; killmonsterall "06guild_0"+ .@room; donpcevent "MVP Summoner#"+ .@room +"::OnEnterMap"; end; } 06guild_01,49,49,4 duplicate(MVP Summoner) MVP Summoner#1 116 06guild_02,49,49,4 duplicate(MVP Summoner) MVP Summoner#2 116 06guild_03,49,49,4 duplicate(MVP Summoner) MVP Summoner#3 116 06guild_04,49,49,4 duplicate(MVP Summoner) MVP Summoner#4 116 06guild_05,49,49,4 duplicate(MVP Summoner) MVP Summoner#5 116 06guild_06,49,49,4 duplicate(MVP Summoner) MVP Summoner#6 116 06guild_07,49,49,4 duplicate(MVP Summoner) MVP Summoner#7 116 06guild_08,49,49,4 duplicate(MVP Summoner) MVP Summoner#8 116 06guild_01 mapflag nowarpto 06guild_02 mapflag nowarpto 06guild_03 mapflag nowarpto 06guild_04 mapflag nowarpto 06guild_05 mapflag nowarpto 06guild_06 mapflag nowarpto 06guild_07 mapflag nowarpto 06guild_08 mapflag nowarpto 06guild_01 mapflag nomemo 06guild_02 mapflag nomemo 06guild_03 mapflag nomemo 06guild_04 mapflag nomemo 06guild_05 mapflag nomemo 06guild_06 mapflag nomemo 06guild_07 mapflag nomemo 06guild_08 mapflag nomemo 06guild_01 mapflag noteleport 06guild_02 mapflag noteleport 06guild_03 mapflag noteleport 06guild_04 mapflag noteleport 06guild_05 mapflag noteleport 06guild_06 mapflag noteleport 06guild_07 mapflag noteleport 06guild_08 mapflag noteleport 06guild_01 mapflag nosave SavePoint 06guild_02 mapflag nosave SavePoint 06guild_03 mapflag nosave SavePoint 06guild_04 mapflag nosave SavePoint 06guild_05 mapflag nosave SavePoint 06guild_06 mapflag nosave SavePoint 06guild_07 mapflag nosave SavePoint 06guild_08 mapflag nosave SavePoint 06guild_01 mapflag nopenalty 06guild_02 mapflag nopenalty 06guild_03 mapflag nopenalty 06guild_04 mapflag nopenalty 06guild_05 mapflag nopenalty 06guild_06 mapflag nopenalty 06guild_07 mapflag nopenalty 06guild_08 mapflag nopenalty
  9. Congratulations on the first days of spring! I present to your attention one of the houses from the game Animal Crossing New Horizons, carefully recreated in RO ... ... directly on the Nintendo Switch OLED Animal Crossing Edition with custom painted joy-cons! .•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•.•°'°•. ns_ac_br Following the theme of the game, I wanted to explore new horizons of the mapping again! The entire location exists only on the console screen, which fits perfectly with the player’s point of view. As you can see, in the video, the console has two modes, which are activated by real buttons on the console. And even a button to turn off the console screen has been implemented, which should lead to the player returning to the place where the console was activated. The architecture of the map and all textures was created entirely by hand in a 3D editor. The console was created literally with a ruler in hand, from the moment of purchase. The appearance is made in the official style of the Nintendo Switch Animal Crossing Edition, but on the OLED version and with a custom paint job. However, the main goal was to ensure that flowers were collected from Ragnarok assets to match the game world. Therefore, this map contains almost all the beautiful flowers that have been found in the official game. In the second part of the video you can see the mods in action: 1) Quiet mode - a mode without monsters (also I can easily add an additional pvp mode if you want) 2) Battle mode - 36 waves of almost all pre-re monsters of the Plant and Insect race and the final 37th wave is a battle with a random boss of the Plant or Insect race (Golden Thief Bug, Mistress, Maya or Lady Tanee). The map is a pocket mini instance in which you can fight in a team on low-level servers (other players will need to go online from their own consoles) or fight solo on high-level servers. You can write what next location you want to see from the games on the Switch or any source (This series can be continued...) The map was made in the Browedit 1 program without rms2 models.
  10. need 7 player to enter a waiting room if 7 people on the room it will create a party
  11. Hello //===== rAthena Script ===========================================| //= Mr.Secrets DressRoom - Custom Request //= 1.5 Added 4th job sprites and item requirements [Racaae] //= https://rathena.org/board/topic/144504-mrsecrets-dressroom-custom-request morocc,167,95,4 script Dress Room#sc 2_M_DYEINGER,{ function RestrictClass; function HasjROCostume; function ChangeAppr; function RestrictClass { .@eaj = eaclass(); if(.@eaj&EAJ_BASEMASK == EAJ_NOVICE) return 0; if(.@eaj&EAJL_2 && roclass(.@eaj|EAJL_UPPER) != -1){ return 1; } return 0; } function HasjROCostume { switch(roclass(eaclass()&EAJ_THIRDMASK|EAJL_THIRD)) { case Job_Guillotine_Cross: case Job_Genetic: case Job_Royal_Guard: case Job_Arch_Bishop: case Job_Mechanic: case Job_Ranger: case Job_Minstrel: case Job_Wanderer: case Job_Warlock: // Uncomment lines below to enable certain job when their respective jRO costume is released and you patched the sprite in your client. //case Job_Sorcerer: //case Job_Sura: //case Job_Rune_Knight: return 1; default: return 0; } } function ChangeAppr { mes .n$; if (Zeny < .cost_dressroom) { mes "You don't have enough Zeny."; .@missingzeny = true; } .@size = getarraysize(.cost_item); if (.@size > 1) { for ( .@i = 0; .@i < .@size; .@i += 2 ) { if (countitem(.cost_item[.@i]) < .cost_item[.@i+1]) { if (!.@missingitem) { mes "You didn't bring what I need. You're missing:"; .@missingitem = true; } mes .cost_item[.@i+1] + "x " + mesitemlink(.cost_item[.@i]); } } } if (.@missingzeny || .@missingitem) close; switch(getarg(1)){ case 0: // Normal Mode setlook LOOK_BODY2,0; changebase getarg(0); set baselook, getarg(0); break; case 1: // jRO Mode if(!HasjROCostume()) return; changebase roclass(eaclass()&EAJ_THIRDMASK|EAJL_THIRD); setlook LOOK_CLOTHES_COLOR,0; setlook LOOK_BODY2,!(getlook(LOOK_BODY2)); //atcommand "@bodystyle " + !(getlook(LOOK_BODY2)); baselook = 0; break; } Zeny -= .cost_dressroom; .@size = getarraysize(.cost_item); if (.@size > 1) { for ( .@i = 0; .@i < .@size; .@i += 2 ) delitem .cost_item[.@i], .cost_item[.@i+1]; } mes "Here you are!"; close; } .@TYPE_CHANGEBASE = 0; .@TYPE_SETLOOK = 1; mes .n$; if (!RestrictClass()){ mes "Your class isn't allowed to use my services."; close; } mes "I can change your appearance to another class of your classline!"; if (HasjROCostume()){ mes "I also have a brand new costume for your class!"; } next; mes .n$; if (.cost_dressroom) mes "At a cost of ^FF0000" + F_InsertComma(.cost_dressroom) + "^000000z"; //displaying needed item list .@size = getarraysize(.cost_item); if (.@size > 1) { for ( .@i = 0; .@i < .@size; .@i += 2 ) mes (.@i+3>.@size?"And ":"") + .cost_item[.@i+1] + "x " + mesitemlink(.cost_item[.@i]); } mes "Which class do you want to change your appearance to?"; next; .@option[0] = roclass(eaclass()&EAJ_UPPERMASK); .@option[1] = roclass(eaclass()&EAJ_UPPERMASK|EAJL_UPPER); .@option[2] = roclass(eaclass()&EAJ_THIRDMASK|EAJL_THIRD); if (.4th) { .@job = roclass(eaclass()&EAJ_THIRDMASK|EAJL_THIRD); .@option[4] = roclass(eaclass(.@job)|EAJL_FOURTH|EAJL_UPPER); } for(.@i = 0; .@i < (.4th?5:4); .@i++) { if (!.@option[.@i] && HasjROCostume() && !getlook(LOOK_BODY2) && .@option[.@i] != baselook) .@menu$ += "New jRO " + jobname(.@option[2]) + " costume"; else if (.@option[.@i] > 0 && .@option[.@i] != baselook) { if (roclass(eaclass()) == .@option[.@i]) .@menu$ += "Restore " + jobname(.@option[.@i]) + " costume"; else .@menu$ += jobname(.@option[.@i]); } .@menu$ += ":"; } if(select(.@menu$)-1 == 3) { //jRO costume ChangeAppr(0,.@TYPE_SETLOOK); } ChangeAppr(.@option[@menu-1],.@TYPE_CHANGEBASE); end; OnPCLoginEvent: if(baselook && .dress_perma){ changebase baselook; } end; OnInit: .n$ = "[Dress Room]"; // NPC Name .dress_perma = 1; //Changes are saved when player logout (1=Yes / 0=No) .4th = true; //Enable changing to 4th job sprite (True / False) .cost_dressroom = 10000; // Zeny Cost setarray .cost_item,6959,1,982,3,983,2; // Item cost - item ID,Amount,item ID,Amount... end; }
  12. Greetings, I'm looking around the forum, but I can't find what I'm looking for. Can someone help me create this kind of gold room script? I appreciate it so much! I appreciate any help you can provide. - Only level 275 can enter the gold room - You need 1,000,000 Zeny to enter the gold room - Inside the dungeon you only have 5 hours to stay on the room and farm for gold once you get outside there will be a 1 day cooldown before you can enter again - You can check the remaining time when you are inside the gold room map by using @grtime - Pvp is on inside the dungeon - If you want to go outside the gold room you need to talk to exit npc and if you die you will be respawn to the respawn area or starting area of the map Hopefully someone can share or help to make this one. Thank you!
  13. Npc value in import\castle_db.yml is mandatory. You can put any name. Map: job3_arch01 Name: Emperium Test Room Npc: Emperium Breaker Save the file and restart the map-server.
  14. Still having this error using latest rA git I already addred the map here in import/castle_db.yml Body: - Id: 100 Map: job3_arch01 Name: Emperium Test Room ClientId: 26 still having that error anyone can help thanks
  15. prt_ext,165,138,5 script PvP Arena 574,{ if(agitcheck()) goto nowoetime; mes "[PvP Battle Room]"; mes "Let's Go!!!!!"; menu "No limit [" + getmapusers("guild_vs3") + "]",pvp1, "Non Donate [" + getmapusers("guild_vs4") + "]",spvp, "Guild vs Guild [" + getmapusers("guild_vs2") + "]",gvg1, "Sinx [" + getmapusers("guild_vs1") + "]",sinx; nowoetime: mes "[PvP Battle Room]"; mes "You cannot enter to PvP Room during WoE!"; close; pvp1: warp "guild_vs3",0,0; announce ""+ strcharinfo(0) +" Has Entered The PVP Room.",bc_all; close; gvg1: warp "guild_vs2",0,0; announce ""+ strcharinfo(0) +" Has Entered The GVG Room.",bc_all; close; spvp: if(countitem(59138) > 0 || countitem(59139) > 0 || countitem(59140) > 0 || countitem(59141) > 0 || countitem(59142) > 0 || countitem(59143) > 0 || countitem(59144) > 0 || countitem(59145) > 0 || countitem(59146) > 0 || countitem(59147) > 0 || countitem(59148) > 0 || countitem(59149) > 0 || countitem(59155) > 0 || countitem(59150) > 0 || countitem(59151) > 0 || countitem(59152) > 0 || countitem(59153) > 0 || countitem(59154) > 0 //donate weapon || countitem(59000) > 0 || countitem(59001) > 0 || countitem(59002) > 0 || countitem(59003) > 0 || countitem(59004) > 0 || countitem(59005) > 0 || countitem(59006) > 0 || countitem(59007) > 0 || countitem(59008) > 0 || countitem(59009) > 0 || countitem(59010) > 0 || countitem(59011) > 0 || countitem(59012) > 0 || countitem(59013) > 0 || countitem(59014) > 0 //Pointers || countitem(501) > 0) goto donator; warp "guild_vs4",0,0; announce ""+ strcharinfo(0) +" Has Entered The PVP Room Non Donate.",bc_all; close; donator: mes "You are a donator you are not allowed to this room"; close; sinx: //Put the Custom Items IDs here setarray .@sinx_CustomItems,59000,59001,59002,59003,59004,59005,59006,59007, 59008,59009,59010,59011,59012,59013,59014,59138,59139,59140, 59141,59142,59143,59144,59145,59146,59147,59148,59149,59150, 59151,59152,59153,59154,59155; clear; mes "[PvP Battle Room]"; mes "This room is for ^0000FFAssassin job only^000000."; if (BaseJob != Job_Assassin) close; switch(select("Enter", "Restricted items list", "Cancel")) { case 1: break; case 2: clear; mes "[PvP Battle Room]"; mes "You can't use the following inside:"; for(.@i = 0; .@i < getarraysize(.@sinx_CustomItems); .@i++) mes "" + getitemname(.@sinx_CustomItems[.@i]); close; case 3: close; } for (.@i = 0; .@i < getarraysize(.@sinx_CustomItems); .@i++) { if (countitem(.@sinx_CustomItems[.@i])) .@has_forbidden[.@count++] =.@sinx_CustomItems[.@i]; } if (.@has_forbidden[0]) { clear; mes "[PvP Battle Room]"; mes "You can't enter the room with the following items in your inventory:"; for(.@i = 0; .@i < getarraysize(.@has_forbidden); .@i++) mes "" + getitemname(.@has_forbidden[.@i]); close; } announce strcharinfo(0) +" has entered the PVP Room Sinx.",bc_all; warp "guild_vs1",0,0; end; //OnPCDieEvent: // set @Die,@Die + 1; // if( @Die % 2 == 0 ) warp "SavePoint",0,0; // end; }
  16. That's your request, right? "only custom item will allowed to use inside the sinx pvp room". Is it allow custom items and block everything else or block custom items and allow everything else?
  17. I still enter the room with a custom item.. i already change the customItem but still can enter
  18. When i enter the sinx room as assassin my character is stuck on this
  19. Your rAthena is outdated. You can update it or use this version below: prt_ext,165,138,5 script PvP Arena 574,{ if(agitcheck()) goto nowoetime; mes "[PvP Battle Room]"; mes "Let's Go!!!!!"; menu "No limit [" + getmapusers("guild_vs3") + "]",pvp1, "Non Donate [" + getmapusers("guild_vs4") + "]",spvp, "Guild vs Guild [" + getmapusers("guild_vs2") + "]",gvg1, "Sinx [" + getmapusers("guild_vs1") + "]",sinx; nowoetime: mes "[PvP Battle Room]"; mes "You cannot enter to PvP Room during WoE!"; close; pvp1: warp "guild_vs3",0,0; announce ""+ strcharinfo(0) +" Has Entered The PVP Room.",bc_all; close; gvg1: warp "guild_vs2",0,0; announce ""+ strcharinfo(0) +" Has Entered The GVG Room.",bc_all; close; spvp: if(countitem(59138) > 0 || countitem(59139) > 0 || countitem(59140) > 0 || countitem(59141) > 0 || countitem(59142) > 0 || countitem(59143) > 0 || countitem(59144) > 0 || countitem(59145) > 0 || countitem(59146) > 0 || countitem(59147) > 0 || countitem(59148) > 0 || countitem(59149) > 0 || countitem(59155) > 0 || countitem(59150) > 0 || countitem(59151) > 0 || countitem(59152) > 0 || countitem(59153) > 0 || countitem(59154) > 0 //donate weapon || countitem(59000) > 0 || countitem(59001) > 0 || countitem(59002) > 0 || countitem(59003) > 0 || countitem(59004) > 0 || countitem(59005) > 0 || countitem(59006) > 0 || countitem(59007) > 0 || countitem(59008) > 0 || countitem(59009) > 0 || countitem(59010) > 0 || countitem(59011) > 0 || countitem(59012) > 0 || countitem(59013) > 0 || countitem(59014) > 0 //Pointers || countitem(501) > 0) goto donator; warp "guild_vs4",0,0; announce ""+ strcharinfo(0) +" Has Entered The PVP Room Non Donate.",bc_all; close; donator: mes "You are a donator you are not allowed to this room"; close; sinx: //Put the Custom Items IDs here setarray .@sinx_CustomItems,2538,2435,2378,2721,13036,13411,1279,13037,13410,1280,2772,2773,2774,1281,1282; clear; mes "[PvP Battle Room]"; mes "This room is for ^0000FFAssassin job only^000000."; if (BaseJob != Job_Assassin) close; switch(select("Enter", "Allowed items list", "Cancel")) { case 1: break; case 2: clear; mes "[PvP Battle Room]"; mes "You can use only the following inside:"; for(.@i = 0; .@i < getarraysize(.@sinx_CustomItems); .@i++) mes "" + getitemname(.@sinx_CustomItems[.@i]); close; case 3: close; } getinventorylist; for (.@i = 0; .@i < @inventorylist_count; .@i++) { .@item_id = @inventorylist_id[.@i]; if (getiteminfo(.@item_id, ITEMINFO_TYPE) != IT_ARMOR && getiteminfo(.@item_id, ITEMINFO_TYPE) != IT_WEAPON && getiteminfo(.@item_id, ITEMINFO_TYPE) != IT_SHADOWGEAR) continue; if (inarray(.@sinx_CustomItems, .@item_id) > -1 || inarray(.@has_forbidden, .@item_id) > -1) continue; .@has_forbidden[.@count++] = .@item_id; } if (.@has_forbidden[0]) { clear; mes "[PvP Battle Room]"; mes "You have forbidden items in your inventory. Store or put them away before entering:"; for(.@i = 0; .@i < getarraysize(.@has_forbidden); .@i++) mes "" + getitemname(.@has_forbidden[.@i]); close; } announce strcharinfo(0) +" has entered the PVP Room Sinx.",bc_all; warp "guild_vs1",0,0; end; //OnPCDieEvent: // set @Die,@Die + 1; // if( @Die % 2 == 0 ) warp "SavePoint",0,0; // end; }
  20. ro_prontera,155,244,5 script Donjon des Rangs 757,{ mes "[^FF0000Évaluateur de Chasseur^000000]"; mes "Je suis l'évaluateur officiel des chasseurs."; mes "Dans quel rang souhaitez-vous être testé ?"; mes "^FF0000Attention^000000: Plus le rang est élevé,"; mes "plus les monstres seront puissants !"; next; switch(select(":Rang D (Novice):Rang C (Intermédiaire):Rang B (Avancé):Rang A (Expert):Rang S (Élite):Information:Quitter")) { case 1: case 2: case 3: case 4: case 5: case 6: set @selected_rank, @menu - 1; // Vérification des prérequis if (BaseLevel < .min_level[@selected_rank]) { mes "[^FF0000Évaluateur de Chasseur^000000]"; mes "Vous êtes encore trop faible pour ce rang."; mes "Niveau minimum requis: " + .min_level[@selected_rank]; mes "Revenez quand vous serez plus fort."; close; } if (Zeny < .entry_cost[@selected_rank]) { mes "[^FF0000Évaluateur de Chasseur^000000]"; mes "Frais d'évaluation: " + .entry_cost[@selected_rank] + " Zeny"; mes "Revenez quand vous aurez assez d'argent."; close; } // Confirmation mes "[^FF0000Évaluateur de Chasseur^000000]"; mes "^FF0000Attention^000000:"; mes "• Puissance des monstres: ×" + .power_multiplier[@selected_rank]; mes "• Récompense en Zeny: " + .MinZeny[@selected_rank] + " - " + .MaxZeny[@selected_rank]; mes "Êtes-vous sûr de vouloir entrer ?"; next; if(select("Oui:Non") == 2) close; // Entrée dans le donjon set Zeny, Zeny - .entry_cost[@selected_rank]; announce "Le chasseur [" + strcharinfo(0) + "] entre dans le donjon de Rang " + .rank_names$[@selected_rank] + "!", bc_all; warp .Map$[@selected_rank], 0, 0; break; case 7: mes "[^FF0000Évaluateur de Chasseur^000000]"; mes "Information sur les rangs :"; mes " "; for(set .@i, 0; .@i < getarraysize(.Map$); set .@i, .@i + 1) { mes "^FF0000Rang " + .rank_names$[.@i] + "^000000"; mes "- Niveau requis : " + .min_level[.@i]; mes "- Coût : " + .entry_cost[.@i] + " Zeny"; mes "- Puissance des monstres : ×" + .power_multiplier[.@i]; mes "- Récompense : " + .MinZeny[.@i] + " - " + .MaxZeny[.@i] + " Zeny"; if (.@i < getarraysize(.Map$) - 1) mes " "; } break; case 8: close; } end; OnInit: // Noms des rangs setarray .rank_names$[0], "D", // Novice "C", // Intermédiaire "B", // Avancé "A", // Expert "S"; // Élite // Maps des rangs setarray .Map$[0], "guild_vs3", // Rang D "guild_vs4", // Rang C "guild_vs5", // Rang B "guild_vs1", // Rang A "guild_vs2"; // Rang S // ID des monstres par rang setarray .MobID[0], 1002, // Rang D 1008, // Rang C 1004, // Rang B 1005, // Rang A 1007; // Rang S // Multiplicateur de puissance par rang setarray .power_multiplier[0], 2, // Rang D: ×2 3, // Rang C: ×3 4, // Rang B: ×4 5, // Rang A: ×5 6; // Rang S: ×6 // Niveau minimum par rang setarray .min_level[0], 150, // Rang D 200, // Rang C 250, // Rang B 300, // Rang A 375; // Rang S // Coût d'entrée par rang setarray .entry_cost[0], 1000000, // Rang D 2000000, // Rang C 4000000, // Rang B 8000000, // Rang A 10000000; // Rang S // Récompenses minimum par rang setarray .MinZeny[0], 100000, // Rang D 200000, // Rang C 400000, // Rang B 800000, // Rang A 1000000; // Rang S // Récompenses maximum par rang setarray .MaxZeny[0], 300000, // Rang D 500000, // Rang C 1000000, // Rang B 1500000, // Rang A 3000000; // Rang S // Initialisation des donjons for(set .@i, 0; .@i < getarraysize(.Map$); set .@i, .@i + 1) { killmonsterall .Map$[.@i]; monster .Map$[.@i],1,1,"--ja--",.MobID[.@i],100,strnpcinfo(0)+"::OnMobKilled"; // Ajustement des stats des monstres spawned for(set .@j, 0; .@j < getarraysize($@mobid); set .@j, .@j + 1) { getunitdata $@mobid[.@j], .@mob_data; setunitdata $@mobid[.@j], 6, .@mob_data[6] * .power_multiplier[.@i]; setunitdata $@mobid[.@j], 7, .@mob_data[7] * .power_multiplier[.@i]; setunitdata $@mobid[.@j], 8, .@mob_data[8] * .power_multiplier[.@i]; setunitdata $@mobid[.@j], 9, .@mob_data[9] * .power_multiplier[.@i]; setunitdata $@mobid[.@j], 10, .@mob_data[10] * .power_multiplier[.@i]; } // Configuration des maps setmapflag .Map$[.@i], mf_nomemo; setmapflag .Map$[.@i], mf_noreturn; setmapflag .Map$[.@i], mf_nowarp; setmapflag .Map$[.@i], mf_noskill; } end; OnMobKilled: // Obtenir le GID du dernier monstre tué set .@mob_gid, killedrid; // Ajustement des stats du monstre selon le rang getunitdata .@mob_gid, .@mob_data; // Utiliser des indices numériques au lieu de noms de constantes // UMOB_MAXHP = 6, UMOB_ATK1 = 7, UMOB_ATK2 = 8, UMOB_DEF = 9, UMOB_MDEF = 10 setunitdata .@mob_gid, 6, .@mob_data[6] * .power_multiplier[@selected_rank]; setunitdata .@mob_gid, 7, .@mob_data[7] * .power_multiplier[@selected_rank]; setunitdata .@mob_gid, 8, .@mob_data[8] * .power_multiplier[@selected_rank]; setunitdata .@mob_gid, 9, .@mob_data[9] * .power_multiplier[@selected_rank]; setunitdata .@mob_gid, 10, .@mob_data[10] * .power_multiplier[@selected_rank]; // Calcul de la récompense set .@zeny_gain, rand(.MinZeny[@selected_rank], .MaxZeny[@selected_rank]); set Zeny, Zeny + .@zeny_gain; dispbottom "Vous avez gagné " + .@zeny_gain + " Zeny!"; // Respawn du monstre monster .Map$[@selected_rank],0,0,"--ja--",.MobID[@selected_rank],1,strnpcinfo(0)+"::OnMobKilled"; end; } Hello, I have no errors in the console but I do not understand why the monsters do not appear once entered in the dungeons do you know why thank you?
  21. Hello, I am a pt-BR and I am not able to pull the data from mysql with accents to the server correctly. Everything that comes and goes to SQL with accents is in error. Exp: NPC PVP Bring the translation via sql: Error src: My inter_athena.conf file: // Athena InterServer configuration. // Contains settings shared/used by more than 1 server. // Options for both versions // Log Inter Connections, etc.? log_inter: 1 // Inter Log Filename inter_log_filename: log/inter.log // Level range for sharing within a party party_share_level: 255 // You can specify the codepage to use in your MySQL tables here. // (Note that this feature requires MySQL 4.1+) default_codepage: utf8mb4 // For IPs, ideally under linux, you want to use localhost instead of 127.0.0.1 // Under windows, you want to use 127.0.0.1. If you see a message like // "Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)" // and you have localhost, switch it to 127.0.0.1 // Global SQL settings // overridden by local settings when the hostname is defined there // (currently only the login-server reads/obeys these settings) // MySQL Login server login_server_ip: 127.0.0.1 login_server_port: 3306 login_server_id: root login_server_pw: login_server_db: login_codepage:utf8mb4 login_case_sensitive: no ipban_db_ip: 127.0.0.1 ipban_db_port: 3306 ipban_db_id: root ipban_db_pw: ipban_db_db: ipban_codepage:utf8mb4 // MySQL Character server char_server_ip: 127.0.0.1 char_server_port: 3306 char_server_id: char_server_pw: char_server_db: // MySQL Map Server map_server_ip: 127.0.0.1 map_server_port: 3306 map_server_id: map_server_pw: map_server_db: // MySQL Log Database log_db_ip: 127.0.0.1 log_db_port: 3306 log_db_id: log_db_pw: log_db_db: log_codepage:utf8mb4 log_login_db: loginlog // MySQL Reconnect Settings // - mysql_reconnect_type: // 1: When MySQL disconnects during runtime, the server tries to reconnect // mysql_reconnect_count times and shuts down if unsuccessful. // 2: When mysql disconnects during runtime, it tries to reconnect indefinitely. mysql_reconnect_type: 2 mysql_reconnect_count: 1 // DO NOT CHANGE ANYTHING BEYOND THIS LINE UNLESS YOU KNOW YOUR DATABASE DAMN WELL // this is meant for people who KNOW their stuff, and for some reason want to change their // database layout. [CLOWNISIUS] // ALL MySQL Database Table names // Login Database Tables login_server_account_db: login ipban_table: ipbanlist // Shared global_acc_reg_num_table: global_acc_reg_num global_acc_reg_str_table: global_acc_reg_str // Char Database Tables char_db: char hotkey_db: hotkey scdata_db: sc_data cart_db: cart_inventory inventory_db: inventory charlog_db: charlog skill_db: skill interlog_db: interlog memo_db: memo guild_db: guild guild_alliance_db: guild_alliance guild_castle_db: guild_castle guild_expulsion_db: guild_expulsion guild_member_db: guild_member guild_skill_db: guild_skill guild_position_db: guild_position guild_storage_db: guild_storage party_db: party pet_db: pet friend_db: friends mail_db: mail mail_attachment_db: mail_attachments auction_db: auction quest_db: quest homunculus_db: homunculus skill_homunculus_db: skill_homunculus mercenary_db: mercenary mercenary_owner_db: mercenary_owner elemental_db: elemental skillcooldown_db: skillcooldown bonus_script_db: bonus_script acc_reg_num_table: acc_reg_num acc_reg_str_table: acc_reg_str char_reg_str_table: char_reg_str char_reg_num_table: char_reg_num clan_table: clan clan_alliance_table: clan_alliance // Map Database Tables buyingstore_table: buyingstores buyingstore_items_table: buyingstore_items item_table: item_db renewal-item_table: item_db_re item2_table: item_db2 renewal-item2_table: item_db2_re item_cash_table: item_cash_db item_cash2_table: item_cash_db2 mob_table: mob_db renewal-mob_table: mob_db_re mob2_table: mob_db2 renewal-mob2_table: mob_db2_re mob_skill_table: mob_skill_db renewal-mob_skill_table: mob_skill_db_re mob_skill2_table: mob_skill_db2 renewal-mob_skill2_table: mob_skill_db2_re mapreg_table: mapreg sales_table: sales vending_table: vendings vending_items_table: vending_items market_table: market roulette_table: db_roulette guild_storage_log: guild_storage_log // Use SQL item_db, mob_db and mob_skill_db for the map server? (yes/no) use_sql_db: no inter_server_conf: inter_server.yml import: conf/import/inter_conf.txt I also edited the sql file: // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder #include "sql.hpp" #ifdef WIN32 #include "winapi.hpp" #endif #include <mysql.h> #include <stdlib.h>// strtoul #include "cbasetypes.hpp" #include "malloc.hpp" #include "showmsg.hpp" #include "strlib.hpp" #include "timer.hpp" // MySQL 8.0 or later removed my_bool typedef. // Reintroduce it as a bandaid fix. // See https://bugs.mysql.com/?id=87337 #if !defined(MARIADB_BASE_VERSION) && !defined(MARIADB_VERSION_ID) && MYSQL_VERSION_ID >= 80001 && MYSQL_VERSION_ID != 80002 #define my_bool bool #endif #define SQL_CONF_NAME "conf/inter_athena.conf" void ra_mysql_error_handler(unsigned int ecode); int mysql_reconnect_type; unsigned int mysql_reconnect_count; /// Sql handle struct Sql { StringBuf buf; MYSQL handle; MYSQL_RES* result; MYSQL_ROW row; unsigned long* lengths; int keepalive; }; // Column length receiver. // Takes care of the possible size missmatch between uint32 and unsigned long. struct s_column_length { uint32* out_length; unsigned long length; }; typedef struct s_column_length s_column_length; /// Sql statement struct SqlStmt { StringBuf buf; MYSQL_STMT* stmt; MYSQL_BIND* params; MYSQL_BIND* columns; s_column_length* column_lengths; size_t max_params; size_t max_columns; bool bind_params; bool bind_columns; }; /////////////////////////////////////////////////////////////////////////////// // Sql Handle /////////////////////////////////////////////////////////////////////////////// /// Allocates and initializes a new Sql handle. Sql* Sql_Malloc(void) { Sql* self; CREATE(self, Sql, 1); mysql_init(&self->handle); StringBuf_Init(&self->buf); self->lengths = NULL; self->result = NULL; self->keepalive = INVALID_TIMER; my_bool reconnect = 1; mysql_options(&self->handle, MYSQL_OPT_RECONNECT, &reconnect); return self; } static int Sql_P_Keepalive(Sql* self); /** * Establishes a connection to schema * @param self : sql handle * @param user : username to access * @param passwd : password * @param host : hostname * @param port : port * @param db : schema name * @return */ int Sql_Connect(Sql* self, const char* user, const char* passwd, const char* host, uint16 port, const char* db) { if( self == NULL ) return SQL_ERROR; StringBuf_Clear(&self->buf); if( !mysql_real_connect(&self->handle, host, user, passwd, db, (unsigned int)port, NULL/*unix_socket*/, 0/*clientflag*/) ) { ShowSQL("%s\n", mysql_error(&self->handle)); return SQL_ERROR; } // Força charset utf8mb4 após conexão Sql_SetEncoding(self, "utf8mb4"); self->keepalive = Sql_P_Keepalive(self); if( self->keepalive == INVALID_TIMER ) { ShowSQL("Failed to establish keepalive for DB connection!\n"); return SQL_ERROR; } return SQL_SUCCESS; } /// Retrieves the timeout of the connection. int Sql_GetTimeout(Sql* self, uint32* out_timeout) { if( self && out_timeout && SQL_SUCCESS == Sql_Query(self, "SHOW VARIABLES LIKE 'wait_timeout'") ) { char* data; size_t len; if( SQL_SUCCESS == Sql_NextRow(self) && SQL_SUCCESS == Sql_GetData(self, 1, &data, &len) ) { *out_timeout = (uint32)strtoul(data, NULL, 10); Sql_FreeResult(self); return SQL_SUCCESS; } Sql_FreeResult(self); } return SQL_ERROR; } /// Retrieves the name of the columns of a table into out_buf, with the separator after each name. int Sql_GetColumnNames(Sql* self, const char* table, char* out_buf, size_t buf_len, char sep) { char* data; size_t len; size_t off = 0; if( self == NULL || SQL_ERROR == Sql_Query(self, "EXPLAIN `%s`", table) ) return SQL_ERROR; out_buf[off] = '\0'; while( SQL_SUCCESS == Sql_NextRow(self) && SQL_SUCCESS == Sql_GetData(self, 0, &data, &len) ) { len = strnlen(data, len); if( off + len + 2 > buf_len ) { ShowDebug("Sql_GetColumns: output buffer is too small\n"); *out_buf = '\0'; return SQL_ERROR; } memcpy(out_buf+off, data, len); off += len; out_buf[off++] = sep; } out_buf[off] = '\0'; Sql_FreeResult(self); return SQL_SUCCESS; } /// Changes the encoding of the connection. int Sql_SetEncoding(Sql* self, const char* encoding) { if( self && Sql_Query(self, "SET NAMES %s", encoding) == 0 ) return SQL_SUCCESS; return SQL_ERROR; } /// Pings the connection. int Sql_Ping(Sql* self) { if( self && mysql_ping(&self->handle) == 0 ) return SQL_SUCCESS; return SQL_ERROR; } /// Wrapper function for Sql_Ping. /// /// @private static TIMER_FUNC(Sql_P_KeepaliveTimer){ Sql* self = (Sql*)data; ShowInfo("Pinging SQL server to keep connection alive...\n"); Sql_Ping(self); return 0; } /// Establishes keepalive (periodic ping) on the connection. /// /// @return the keepalive timer id, or INVALID_TIMER /// @private static int Sql_P_Keepalive(Sql* self) { uint32 timeout, ping_interval; // set a default value first timeout = 28800; // 8 hours // request the timeout value from the mysql server Sql_GetTimeout(self, &timeout); if( timeout < 60 ) timeout = 60; // establish keepalive ping_interval = timeout - 30; // 30-second reserve //add_timer_func_list(Sql_P_KeepaliveTimer, "Sql_P_KeepaliveTimer"); return add_timer_interval(gettick() + ping_interval*1000, Sql_P_KeepaliveTimer, 0, (intptr_t)self, ping_interval*1000); } /// Escapes a string. size_t Sql_EscapeString(Sql* self, char *out_to, const char *from) { if( self ) return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)strlen(from)); else return (size_t)mysql_escape_string(out_to, from, (unsigned long)strlen(from)); } /// Escapes a string. size_t Sql_EscapeStringLen(Sql* self, char *out_to, const char *from, size_t from_len) { if( self ) return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)from_len); else return (size_t)mysql_escape_string(out_to, from, (unsigned long)from_len); } /// Executes a query. int Sql_Query(Sql* self, const char* query, ...) { int res; va_list args; va_start(args, query); res = Sql_QueryV(self, query, args); va_end(args); return res; } /// Executes a query. int Sql_QueryV(Sql* self, const char* query, va_list args) { if( self == NULL ) return SQL_ERROR; Sql_FreeResult(self); StringBuf_Clear(&self->buf); StringBuf_Vprintf(&self->buf, query, args); if( mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) { ShowSQL("DB error - %s\n", mysql_error(&self->handle)); ra_mysql_error_handler(mysql_errno(&self->handle)); return SQL_ERROR; } self->result = mysql_store_result(&self->handle); if( mysql_errno(&self->handle) != 0 ) { ShowSQL("DB error - %s\n", mysql_error(&self->handle)); ra_mysql_error_handler(mysql_errno(&self->handle)); return SQL_ERROR; } return SQL_SUCCESS; } /// Executes a query. int Sql_QueryStr(Sql* self, const char* query) { if( self == NULL ) return SQL_ERROR; Sql_FreeResult(self); StringBuf_Clear(&self->buf); StringBuf_AppendStr(&self->buf, query); if( mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) { ShowSQL("DB error - %s\n", mysql_error(&self->handle)); ra_mysql_error_handler(mysql_errno(&self->handle)); return SQL_ERROR; } self->result = mysql_store_result(&self->handle); if( mysql_errno(&self->handle) != 0 ) { ShowSQL("DB error - %s\n", mysql_error(&self->handle)); ra_mysql_error_handler(mysql_errno(&self->handle)); return SQL_ERROR; } return SQL_SUCCESS; } /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE query. uint64 Sql_LastInsertId(Sql* self) { if( self ) return (uint64)mysql_insert_id(&self->handle); else return 0; } /// Returns the number of columns in each row of the result. uint32 Sql_NumColumns(Sql* self) { if( self && self->result ) return (uint32)mysql_num_fields(self->result); return 0; } /// Returns the number of rows in the result. uint64 Sql_NumRows(Sql* self) { if( self && self->result ) return (uint64)mysql_num_rows(self->result); return 0; } /// Returns the number of rows affected by the last query uint64 Sql_NumRowsAffected(Sql* self) { if( self ) return (uint64)mysql_affected_rows(&self->handle); return 0; } /// Fetches the next row. int Sql_NextRow(Sql* self) { if( self && self->result ) { self->row = mysql_fetch_row(self->result); if( self->row ) { self->lengths = mysql_fetch_lengths(self->result); return SQL_SUCCESS; } self->lengths = NULL; if( mysql_errno(&self->handle) == 0 ) return SQL_NO_DATA; } return SQL_ERROR; } /// Gets the data of a column. int Sql_GetData(Sql* self, size_t col, char** out_buf, size_t* out_len) { if( self && self->row ) { if( col < Sql_NumColumns(self) ) { if( out_buf ) *out_buf = self->row[col]; if( out_len ) *out_len = (size_t)self->lengths[col]; } else {// out of range - ignore if( out_buf ) *out_buf = NULL; if( out_len ) *out_len = 0; } return SQL_SUCCESS; } return SQL_ERROR; } /// Frees the result of the query. void Sql_FreeResult(Sql* self) { if( self && self->result ) { mysql_free_result(self->result); self->result = NULL; self->row = NULL; self->lengths = NULL; } } /// Shows debug information (last query). void Sql_ShowDebug_(Sql* self, const char* debug_file, const unsigned long debug_line) { if( self == NULL ) ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); else if( StringBuf_Length(&self->buf) > 0 ) ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); else ShowDebug("at %s:%lu\n", debug_file, debug_line); } /// Frees a Sql handle returned by Sql_Malloc. void Sql_Free(Sql* self) { if( self ) { Sql_FreeResult(self); StringBuf_Destroy(&self->buf); if( self->keepalive != INVALID_TIMER ) delete_timer(self->keepalive, Sql_P_KeepaliveTimer); aFree(self); } } /////////////////////////////////////////////////////////////////////////////// // Prepared Statements /////////////////////////////////////////////////////////////////////////////// /// Returns the mysql integer type for the target size. /// /// @private static enum enum_field_types Sql_P_SizeToMysqlIntType(int sz) { switch( sz ) { case 1: return MYSQL_TYPE_TINY; case 2: return MYSQL_TYPE_SHORT; case 4: return MYSQL_TYPE_LONG; case 8: return MYSQL_TYPE_LONGLONG; default: ShowDebug("SizeToMysqlIntType: unsupported size (%d)\n", sz); return MYSQL_TYPE_NULL; } } /// Binds a parameter/result. /// /// @private static int Sql_P_BindSqlDataType(MYSQL_BIND* bind, enum SqlDataType buffer_type, void* buffer, size_t buffer_len, unsigned long* out_length, int8* out_is_null) { memset(bind, 0, sizeof(MYSQL_BIND)); switch( buffer_type ) { case SQLDT_NULL: bind->buffer_type = MYSQL_TYPE_NULL; buffer_len = 0;// FIXME length = ? [FlavioJS] break; // fixed size case SQLDT_UINT8: bind->is_unsigned = 1; case SQLDT_INT8: bind->buffer_type = MYSQL_TYPE_TINY; buffer_len = 1; break; case SQLDT_UINT16: bind->is_unsigned = 1; case SQLDT_INT16: bind->buffer_type = MYSQL_TYPE_SHORT; buffer_len = 2; break; case SQLDT_UINT32: bind->is_unsigned = 1; case SQLDT_INT32: bind->buffer_type = MYSQL_TYPE_LONG; buffer_len = 4; break; case SQLDT_UINT64: bind->is_unsigned = 1; case SQLDT_INT64: bind->buffer_type = MYSQL_TYPE_LONGLONG; buffer_len = 8; break; // platform dependent size case SQLDT_UCHAR: bind->is_unsigned = 1; case SQLDT_CHAR: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(char)); buffer_len = sizeof(char); break; case SQLDT_USHORT: bind->is_unsigned = 1; case SQLDT_SHORT: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(short)); buffer_len = sizeof(short); break; case SQLDT_UINT: bind->is_unsigned = 1; case SQLDT_INT: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int)); buffer_len = sizeof(int); break; case SQLDT_ULONG: bind->is_unsigned = 1; case SQLDT_LONG: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(long)); buffer_len = sizeof(long); break; case SQLDT_ULONGLONG: bind->is_unsigned = 1; case SQLDT_LONGLONG: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int64)); buffer_len = sizeof(int64); break; // floating point case SQLDT_FLOAT: bind->buffer_type = MYSQL_TYPE_FLOAT; buffer_len = 4; break; case SQLDT_DOUBLE: bind->buffer_type = MYSQL_TYPE_DOUBLE; buffer_len = 8; break; // other case SQLDT_STRING: case SQLDT_ENUM: bind->buffer_type = MYSQL_TYPE_STRING; break; case SQLDT_BLOB: bind->buffer_type = MYSQL_TYPE_BLOB; break; default: ShowDebug("Sql_P_BindSqlDataType: unsupported buffer type (%d)\n", buffer_type); return SQL_ERROR; } bind->buffer = buffer; bind->buffer_length = (unsigned long)buffer_len; bind->length = out_length; bind->is_null = (my_bool*)out_is_null; return SQL_SUCCESS; } /// Prints debug information about a field (type and length). /// /// @private static void Sql_P_ShowDebugMysqlFieldInfo(const char* prefix, enum enum_field_types type, int is_unsigned, unsigned long length, const char* length_postfix) { const char* sign = (is_unsigned ? "UNSIGNED " : ""); const char* type_string; switch( type ) { default: ShowDebug("%stype=%s%u, length=%lu\n", prefix, sign, type, length); return; #define SHOW_DEBUG_OF(x) case x: type_string = #x; break SHOW_DEBUG_OF(MYSQL_TYPE_TINY); SHOW_DEBUG_OF(MYSQL_TYPE_SHORT); SHOW_DEBUG_OF(MYSQL_TYPE_LONG); SHOW_DEBUG_OF(MYSQL_TYPE_INT24); SHOW_DEBUG_OF(MYSQL_TYPE_LONGLONG); SHOW_DEBUG_OF(MYSQL_TYPE_DECIMAL); SHOW_DEBUG_OF(MYSQL_TYPE_FLOAT); SHOW_DEBUG_OF(MYSQL_TYPE_DOUBLE); SHOW_DEBUG_OF(MYSQL_TYPE_TIMESTAMP); SHOW_DEBUG_OF(MYSQL_TYPE_DATE); SHOW_DEBUG_OF(MYSQL_TYPE_TIME); SHOW_DEBUG_OF(MYSQL_TYPE_DATETIME); SHOW_DEBUG_OF(MYSQL_TYPE_YEAR); SHOW_DEBUG_OF(MYSQL_TYPE_STRING); SHOW_DEBUG_OF(MYSQL_TYPE_VAR_STRING); SHOW_DEBUG_OF(MYSQL_TYPE_BLOB); SHOW_DEBUG_OF(MYSQL_TYPE_SET); SHOW_DEBUG_OF(MYSQL_TYPE_ENUM); SHOW_DEBUG_OF(MYSQL_TYPE_NULL); #undef SHOW_DEBUG_TYPE_OF } ShowDebug("%stype=%s%s, length=%lu%s\n", prefix, sign, type_string, length, length_postfix); } /// Reports debug information about a truncated column. /// /// @private static void SqlStmt_P_ShowDebugTruncatedColumn(SqlStmt* self, size_t i) { MYSQL_RES* meta; MYSQL_FIELD* field; MYSQL_BIND* column; meta = mysql_stmt_result_metadata(self->stmt); field = mysql_fetch_field_direct(meta, (unsigned int)i); ShowSQL("DB error - data of field '%s' was truncated.\n", field->name); ShowDebug("column - %lu\n", (unsigned long)i); Sql_P_ShowDebugMysqlFieldInfo("data - ", field->type, field->flags&UNSIGNED_FLAG, self->column_lengths[i].length, ""); column = &self->columns[i]; if( column->buffer_type == MYSQL_TYPE_STRING ) Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, "+1(nul-terminator)"); else Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, ""); mysql_free_result(meta); } /// Allocates and initializes a new SqlStmt handle. SqlStmt* SqlStmt_Malloc(Sql* sql) { SqlStmt* self; MYSQL_STMT* stmt; if( sql == NULL ) return NULL; stmt = mysql_stmt_init(&sql->handle); if( stmt == NULL ) { ShowSQL("DB error - %s\n", mysql_error(&sql->handle)); return NULL; } CREATE(self, SqlStmt, 1); StringBuf_Init(&self->buf); self->stmt = stmt; self->params = NULL; self->columns = NULL; self->column_lengths = NULL; self->max_params = 0; self->max_columns = 0; self->bind_params = false; self->bind_columns = false; return self; } /// Prepares the statement. int SqlStmt_Prepare(SqlStmt* self, const char* query, ...) { int res; va_list args; va_start(args, query); res = SqlStmt_PrepareV(self, query, args); va_end(args); return res; } /// Prepares the statement. int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args) { if( self == NULL ) return SQL_ERROR; SqlStmt_FreeResult(self); StringBuf_Clear(&self->buf); StringBuf_Vprintf(&self->buf, query, args); if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) { ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); ra_mysql_error_handler(mysql_stmt_errno(self->stmt)); return SQL_ERROR; } self->bind_params = false; return SQL_SUCCESS; } /// Prepares the statement. int SqlStmt_PrepareStr(SqlStmt* self, const char* query) { if( self == NULL ) return SQL_ERROR; SqlStmt_FreeResult(self); StringBuf_Clear(&self->buf); StringBuf_AppendStr(&self->buf, query); if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) { ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); ra_mysql_error_handler(mysql_stmt_errno(self->stmt)); return SQL_ERROR; } self->bind_params = false; return SQL_SUCCESS; } /// Returns the number of parameters in the prepared statement. size_t SqlStmt_NumParams(SqlStmt* self) { if( self ) return (size_t)mysql_stmt_param_count(self->stmt); else return 0; } /// Binds a parameter to a buffer. int SqlStmt_BindParam(SqlStmt* self, size_t idx, enum SqlDataType buffer_type, void* buffer, size_t buffer_len) { if( self == NULL ) return SQL_ERROR; if( !self->bind_params ) {// initialize the bindings size_t i; size_t count; count = SqlStmt_NumParams(self); if( self->max_params < count ) { self->max_params = count; RECREATE(self->params, MYSQL_BIND, count); } memset(self->params, 0, count*sizeof(MYSQL_BIND)); for( i = 0; i < count; ++i ) self->params[i].buffer_type = MYSQL_TYPE_NULL; self->bind_params = true; } if( idx < self->max_params ) return Sql_P_BindSqlDataType(self->params+idx, buffer_type, buffer, buffer_len, NULL, NULL); else return SQL_SUCCESS;// out of range - ignore } /// Executes the prepared statement. int SqlStmt_Execute(SqlStmt* self) { if( self == NULL ) return SQL_ERROR; SqlStmt_FreeResult(self); if( (self->bind_params && mysql_stmt_bind_param(self->stmt, self->params)) || mysql_stmt_execute(self->stmt) ) { ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); ra_mysql_error_handler(mysql_stmt_errno(self->stmt)); return SQL_ERROR; } self->bind_columns = false; if( mysql_stmt_store_result(self->stmt) )// store all the data { ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); ra_mysql_error_handler(mysql_stmt_errno(self->stmt)); return SQL_ERROR; } return SQL_SUCCESS; } /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE statement. uint64 SqlStmt_LastInsertId(SqlStmt* self) { if( self ) return (uint64)mysql_stmt_insert_id(self->stmt); else return 0; } /// Returns the number of columns in each row of the result. size_t SqlStmt_NumColumns(SqlStmt* self) { if( self ) return (size_t)mysql_stmt_field_count(self->stmt); else return 0; } /// Binds the result of a column to a buffer. int SqlStmt_BindColumn(SqlStmt* self, size_t idx, enum SqlDataType buffer_type, void* buffer, size_t buffer_len, uint32* out_length, int8* out_is_null) { if( self == NULL ) return SQL_ERROR; if( buffer_type == SQLDT_STRING || buffer_type == SQLDT_ENUM ) { if( buffer_len < 1 ) { ShowDebug("SqlStmt_BindColumn: buffer_len(%" PRIuPTR ") is too small, no room for the nul-terminator\n", buffer_len); return SQL_ERROR; } --buffer_len;// nul-terminator } if( !self->bind_columns ) {// initialize the bindings size_t i; size_t cols; cols = SqlStmt_NumColumns(self); if( self->max_columns < cols ) { self->max_columns = cols; RECREATE(self->columns, MYSQL_BIND, cols); RECREATE(self->column_lengths, s_column_length, cols); } memset(self->columns, 0, cols*sizeof(MYSQL_BIND)); memset(self->column_lengths, 0, cols*sizeof(s_column_length)); for( i = 0; i < cols; ++i ) self->columns[i].buffer_type = MYSQL_TYPE_NULL; self->bind_columns = true; } if( idx < self->max_columns ) { self->column_lengths[idx].out_length = out_length; return Sql_P_BindSqlDataType(self->columns+idx, buffer_type, buffer, buffer_len, &self->column_lengths[idx].length, out_is_null); } else { return SQL_SUCCESS;// out of range - ignore } } /// Returns the number of rows in the result. uint64 SqlStmt_NumRows(SqlStmt* self) { if( self ) return (uint64)mysql_stmt_num_rows(self->stmt); else return 0; } /// Fetches the next row. int SqlStmt_NextRow(SqlStmt* self) { int err; size_t i; size_t cols; if( self == NULL ) return SQL_ERROR; // bind columns if( self->bind_columns && mysql_stmt_bind_result(self->stmt, self->columns) ) err = 1;// error binding columns else err = mysql_stmt_fetch(self->stmt);// fetch row // check for errors if( err == MYSQL_NO_DATA ) return SQL_NO_DATA; #if defined(MYSQL_DATA_TRUNCATED) // MySQL 5.0/5.1 defines and returns MYSQL_DATA_TRUNCATED [FlavioJS] if( err == MYSQL_DATA_TRUNCATED ) { my_bool truncated; if( !self->bind_columns ) { ShowSQL("DB error - data truncated (unknown source, columns are not bound)\n"); return SQL_ERROR; } // find truncated column cols = SqlStmt_NumColumns(self); for( i = 0; i < cols; ++i ) { MYSQL_BIND* column = &self->columns[i]; column->error = &truncated; mysql_stmt_fetch_column(self->stmt, column, (unsigned int)i, 0); column->error = NULL; if( truncated ) {// report truncated column SqlStmt_P_ShowDebugTruncatedColumn(self, i); return SQL_ERROR; } } ShowSQL("DB error - data truncated (unknown source)\n"); return SQL_ERROR; } #endif if( err ) { ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); ra_mysql_error_handler(mysql_stmt_errno(self->stmt)); return SQL_ERROR; } // propagate column lengths and clear unused parts of string/enum/blob buffers cols = SqlStmt_NumColumns(self); for( i = 0; i < cols; ++i ) { unsigned long length = self->column_lengths[i].length; MYSQL_BIND* column = &self->columns[i]; #if !defined(MYSQL_DATA_TRUNCATED) // MySQL 4.1/(below?) returns success even if data is truncated, so we test truncation manually [FlavioJS] if( column->buffer_length < length ) {// report truncated column if( column->buffer_type == MYSQL_TYPE_STRING || column->buffer_type == MYSQL_TYPE_BLOB ) {// string/enum/blob column SqlStmt_P_ShowDebugTruncatedColumn(self, i); return SQL_ERROR; } // FIXME numeric types and null [FlavioJS] } #endif if( self->column_lengths[i].out_length ) *self->column_lengths[i].out_length = (uint32)length; if( column->buffer_type == MYSQL_TYPE_STRING ) {// clear unused part of the string/enum buffer (and nul-terminate) memset((char*)column->buffer + length, 0, column->buffer_length - length + 1); } else if( column->buffer_type == MYSQL_TYPE_BLOB && length < column->buffer_length ) {// clear unused part of the blob buffer memset((char*)column->buffer + length, 0, column->buffer_length - length); } } return SQL_SUCCESS; } /// Frees the result of the statement execution. void SqlStmt_FreeResult(SqlStmt* self) { if( self ) mysql_stmt_free_result(self->stmt); } /// Shows debug information (with statement). void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned long debug_line) { if( self == NULL ) ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); else if( StringBuf_Length(&self->buf) > 0 ) ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); else ShowDebug("at %s:%lu\n", debug_file, debug_line); } /// Frees a SqlStmt returned by SqlStmt_Malloc. void SqlStmt_Free(SqlStmt* self) { if( self ) { SqlStmt_FreeResult(self); StringBuf_Destroy(&self->buf); mysql_stmt_close(self->stmt); if( self->params ) aFree(self->params); if( self->columns ) { aFree(self->columns); aFree(self->column_lengths); } aFree(self); } } /// Receives MySQL error codes during runtime (not on first-time-connects). void ra_mysql_error_handler(unsigned int ecode) { switch( ecode ) { case 2003:// Can't connect to MySQL (this error only happens here when failing to reconnect) if( mysql_reconnect_type == 1 ) { static unsigned int retry = 1; if( ++retry > mysql_reconnect_count ) { ShowFatalError("MySQL has been unreachable for too long, %d reconnects were attempted. Shutting Down\n", retry); exit(EXIT_FAILURE); } } break; } } void Sql_inter_server_read(const char* cfgName, bool first) { char line[1024], w1[1024], w2[1024]; FILE* fp; fp = fopen(cfgName, "r"); if(fp == NULL) { if( first ) { ShowFatalError("File not found: %s\n", cfgName); exit(EXIT_FAILURE); } else ShowError("File not found: %s\n", cfgName); return; } while(fgets(line, sizeof(line), fp)) { int i = sscanf(line, "%1023[^:]: %1023[^\r\n]", w1, w2); if(i != 2) continue; if(!strcmpi(w1,"mysql_reconnect_type")) { mysql_reconnect_type = atoi(w2); switch( mysql_reconnect_type ) { case 1: case 2: break; default: ShowError("%s::mysql_reconnect_type is set to %d which is not valid, defaulting to 1...\n", cfgName, mysql_reconnect_type); mysql_reconnect_type = 1; break; } } else if(!strcmpi(w1,"mysql_reconnect_count")) { mysql_reconnect_count = atoi(w2); if( mysql_reconnect_count < 1 ) mysql_reconnect_count = 1; } else if(!strcmpi(w1,"import")) Sql_inter_server_read(w2,false); } fclose(fp); return; } void Sql_Init(void) { Sql_inter_server_read(SQL_CONF_NAME,true); } #ifdef my_bool #undef my_bool #endif Help =[
  22. I have a custom status effect, a.k.a SC_INVASION_E which is customized. Now I want my custom status to detect if a player is in a chatroom/pub. Initially, I edited chat.cpp in the chat_createpcchat function, and it works for detecting when a chatroom is created. However, my problem is that it doesn’t detect when a player joins a chatroom. To avoid modifying chat.cpp further, I want to handle this detection in my custom status function instead. The issue is that I don’t know the correct function for detecting chatrooms; I used SC_NOCHAT if (sd->sc.getSCE(SC_NOCHAT)) { status_change_end(&sd->bl, SC_INVASION_E); clif_displaymessage(sd->fd, "Invasion Spirit Off - close/leave chatroom and activate again"); return 0; }
  23. hello anybody know how to fix this error everytime the player enter the pvp room this error appears heres the script
  24. I did this basic script, maybe it will help you. CREATE TABLE IF NOT EXISTS `pvp_rank` ( `char_id` int(11) unsigned NOT NULL, `kills` int(11) unsigned NOT NULL DEFAULT 0, `deaths` int(11) unsigned NOT NULL DEFAULT 0, PRIMARY KEY (`char_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; And here's the script. prontera,196,142,5 script PVP Warper 100,{ mes "[ ^FF0000PVP Warper^000000 ]"; mes "Welcome, ^0000FF"+strcharinfo(0)+"^000000."; mes "Please select a PVP room:"; next; // Dynamic menu with player counts .@menu$ = ""; for (.@i = 0; .@i < getarraysize(.pvp_map$); .@i++) { .@users = getmapusers(.pvp_map$[.@i]); .@menu$ += .pvp_name$[.@i]+" ["+.@users+"/"+.pvp_max[.@i]+"]:"; } .@sel = select(.@menu$) - 1; if (BaseLevel < .pvp_level[.@sel]) { mes "[ ^FF0000PVP Warper^000000 ]"; mes "You must be at least level "+.pvp_level[.@sel]+" to enter this room."; close; } if (getmapusers(.pvp_map$[.@sel]) >= .pvp_max[.@sel]) { mes "[ ^FF0000PVP Warper^000000 ]"; mes "This room has reached its player limit ("+.pvp_max[.@sel]+")."; close; } warp .pvp_map$[.@sel],0,0; end; OnPCKillEvent: // Validate if map is a valid PVP room .@valid = 0; for (.@i = 0; .@i < getarraysize(.pvp_map$); .@i++) { if (strcharinfo(3) == .pvp_map$[.@i]) { .@valid = 1; break; } } if (!.@valid) end; // Get Killer and Victim Char IDs safely .@killer_cid = getcharid(0); .@victim_cid = getcharid(0, rid2name(killedrid)); if (!.@killer_cid || !.@victim_cid || .@killer_cid == .@victim_cid) end; // Always register kills and deaths for all maps query_sql("INSERT INTO pvp_rank (`char_id`, `kills`, `deaths`) VALUES ("+.@killer_cid+",1,0),("+.@victim_cid+",0,1) ON DUPLICATE KEY UPDATE `kills`=`kills`+VALUES(`kills`), `deaths`=`deaths`+VALUES(`deaths`)"); // Only grant special points in the GM-selected map if (strcharinfo(3) != .points_map$) end; // IP check validation (enabled or disabled by admin) if (.ip_check_enabled) { query_sql("SELECT last_ip FROM login WHERE account_id="+getcharid(3), .@killer_ip$); query_sql("SELECT last_ip FROM login WHERE account_id="+killedrid, .@victim_ip$); if (.@killer_ip$ == .@victim_ip$) { dispbottom "[PVP Warper]: No points granted. Same IP detected."; end; } } // Kill cooldown validation .@current_time = gettimetick(2); .@cooldown = .kill_cooldown; .@kill_cd_var$ = "kill_cd_"+.@killer_cid+"_"+.@victim_cid; if (getd(.@kill_cd_var$) + .@cooldown > .@current_time) { dispbottom "[PVP Warper]: You recently killed this player. Wait before earning more points."; end; } setd .@kill_cd_var$, .@current_time; // Add your special points reward code here. // Example: set pvp_points, pvp_points + 1; dispbottom "[PVP Warper]: You've earned special points for defeating a player."; end; OnCheckRank: mes "[ ^FF0000PVP Warper^000000 ]"; query_sql("SELECT kills, deaths FROM pvp_rank WHERE char_id="+ getcharid(0), .@kills, .@deaths); mes "Tus estadísticas actuales:"; mes "^0000FFKills:^000000 "+ (.@kills ? .@kills : 0); mes "^FF0000Muertes:^000000 "+ (.@deaths ? .@deaths : 0); close; OnGMResetRank: if (getgmlevel() < 60) { dispbottom "No tienes permisos para usar este comando."; end; } query_sql("TRUNCATE TABLE pvp_rank"); dispbottom "Ranking PVP reiniciado correctamente."; end; OnInit: // General Configuration setarray .pvp_map$[0], "guild_vs1", "guild_vs2", "pvp_y_1-2"; setarray .pvp_name$[0], "PVP Room 1", "PVP Room 2", "PVP Prontera"; setarray .pvp_level[0], 1, 50, 99; setarray .pvp_max[0], 10, 15, 20; // Enable or disable IP check (1 = ON, 0 = OFF) .ip_check_enabled = 0; // Kill cooldown in seconds (recommended: 60-120 sec) .kill_cooldown = 60; // GM configuration: Set the map that gives special points here (default is room 1) .points_map$ = .pvp_map$[0]; // Change [0] to [1] or [2] to switch rooms // Commands for player and GM bindatcmd "pvprank",strnpcinfo(3)+"::OnCheckRank"; bindatcmd "resetpvprank",strnpcinfo(3)+"::OnGMResetRank",60,60; end; } Feel free to ask for a change.
  25. try this. i haven't tested it. /* ALTER TABLE `char` ADD `pvp_kill` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `fame`; */ payon,193,104,4 script PVP Warper 630,{ doevent "pvp_rank_main::OnTalk"; } - script pvp_rank_main -1,{ OnTalk: mes "[PvP Room Master]"; mes "Where do you want to go?"; next; switch ( select ( "Grand Arena [ "+getmapusers("grandarena")+" ]", "^ff0000[ No Points ]^000000 Izlude PVP Room [ "+getmapusers("pvp_y_1-2")+" ]", ( getgmlevel() >= 99 ) ? "^FF0000[GM] Reset PVP Ranking^000000":"" )) { case 1: // Grand Arena if ( getmapusers("grandarena") >= 100 ) { mes "The Grand Arena is full!"; close; } if ( BaseLevel < 50 ) { mes "Excuse me, but"; mes "you need to be at least level 50 or above!"; close; } warp "grandarena",0,0; announce ""+strcharinfo(0)+" entered Grand Arena PVP ROOM!", bc_all, 0xCCFFFF; end; case 2: // Izlude PVP Room if ( getmapusers("pvp_y_1-2") >= 100 ) { mes "The Izlude PVP Room is full!"; close; } if ( BaseLevel < 50 ) { mes "Excuse me, but"; mes "you need to be at least level 50 or above!"; close; } warp "pvp_y_1-2",0,0; announce ""+strcharinfo(0)+" entered Izlude PVP ROOM!", bc_all, 0xCCFFFF; end; case 3: // GM Reset Ranking if ( getgmlevel() < 99 ) { mes "You do not have permission to perform this action."; close; } mes "[PvP Room Master]"; mes "Reset Ranking? This action cannot be undone."; if ( select( "Confirm", "Cancel" ) == 1 ) { query_sql( "UPDATE `char` SET `pvp_kill` = 0 WHERE `pvp_kill` > 0" ); mes "PvP ranking has been reset."; } close; default: // PvP Rankings mes "[PvP Room Master]"; mes "PvP Rankings:"; query_sql( "SELECT `name`, `pvp_kill` FROM `char` WHERE `pvp_kill` > 0 ORDER BY `pvp_kill` DESC LIMIT 10", .@name$, .@pvp_kill ); .@size = getarraysize( .@name$ ); if ( .@size == 0 ) { mes "No PvP rankings available yet."; } else { for ( .@i = 0; .@i < .@size; .@i++ ) { mes "["+(.@i + 1 )+"] "+.@name$[.@i]+" - "+.@pvp_kill[.@i]+" kill(s)"; } } close; } }
×
×
  • Create New...