Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 12/14/14 in all areas

  1. So basically this was going to be something of a surprise. I've been working on this script since January, not constantly just occasionally. It works - kinda... The script runs fine if I don't include the heuristic... But when I do it stops about half way through ama_dun01. I think without the heuristic It takes approximately 3 minutes to complete ama_dun01. Why am I posting this here? Well simply put I don't have enough time to work on it at the moment, and it's just going to disappear forever if I don't. So what I'm asking is for anyone to optimize this and maybe help me figure out why it's stopping with the heuristic value. Before anyone says it, if they even do. Yeah it would be faster on Hercules because of unlimited arrays and ++.@r but that's obvious. I want this to work on rAthena . I'll try to update this topic when I get some more time. ( I've got a few other projects to finish first. ) Thanks in advance any input on this is appreciated. ( There are a few bits I left out because they were mainly for debug/or were part of the main event which I felt wasn't developed enough. ) //Diagonal = 14 //} G //Adjacent = 10 //} G function script abs { //.@v = getarg(0); //.@mask = .@v >> 4 * 8 - 1; //return ((.@v + .@mask) ^ .@mask); .@i = getarg(0); return ( (.@i < 0) ? -.@i : .@i ); } function script max { .@i = ((getarg(0) > getarg(1)) ? getarg(0) : getarg(1)); return .@i; //return getarg(0) ^ ((getarg(0) ^ getarg(1)) & -(getarg(0) < getarg(1))); } ama_dun01,233,9,3 script npc_go 100,{ OnGo: setarray .@dx, 1, 1, 0, -1, -1, -1, 0, 1; setarray .@dy, 0, 1, 1, 1, 0, -1, -1, -1; .@x = 233; //Start Pos .@y = 11; //Start Pos .@s_x = 233; //Start Pos .@s_y = 11; //Start Pos .@len = getarraysize(.@dx); .@e_x = .e_x; //End Pos .@e_y = .e_y; //End Pos .@map_size = 240*240; .@g = 0; dispbottom .@x+"!="+.@e_x+"&&"+.@y+"!="+.@e_y+"||"+.@q+"<"+.@map_size; debugmes "-------------Starting---------------"; set(.@time,gettimetick(0)); freeloop(1); setarray getd(".@node_x"+.@x+"y"+.@y+"c"), 1, .@x, .@y; .@v = 1; .@ar[getarraysize(.@ar)] = .@v; while( .@q<.@map_size ) { LOOP4: set(.@x2,.@x+.@dx[.@a]); set(.@y2,.@y+.@dy[.@a]); .@mes$ = .@x2+" "+.@y2+" "+.@v+" "+.@a+"|"+.@x+" "+.@y; set(.@tmp5$,".@node_x"+.@x2+"y"+.@y2); //----------------------------------------------------> (".@node_x"+.@x2+"y"+.@y2) Temp string. copyarray .@tc_ary, getd(.@tmp5$+"c"), 6; //-------------------------------------------------> .@tc_ary = "Testing closed-list array(node)". if( !.@tc_ary ) { //.@a++; .@q++; continue; } //---------------------------------------------> Challenge closed node. if(checkcell("ama_dun01",.@x2,.@y2,cell_chkwall) || checkcell("ama_dun01",.@x2,.@y2,cell_chkcliff) || checkcell("ama_dun01",.@x2,.@y2,cell_chkwater) || checkcell("ama_dun01",.@x2,.@y2,cell_chknopass) || checkcell("ama_dun01",.@x2,.@y2,cell_chknoreach)) { //---------------------------------> Challenge turf walk-able. .@mes$ = .@mes$+" Not valid turf!"; } else { set .@a$, .@tmp5$+"o"; //-------------------------------------------------------------> (".@node_x"+.@x2+"y"+.@y2+"o") Open-list node. copyarray .@to_ary, getd(.@a$), 6; //-------------------------------------------------> .@to_ary = "Testing open-list array(node)". set(.@m,!.@dx[.@a]||!.@dy[.@a]?10:14); //---------------------------------------------> Challenge diagonal. //dispbottom "Parent G: "+getd(".@node_x"+.@to_ary[1]+"y"+.@to_ary[2]+"c[0]"); //if(.@to_ary) { set(.@g,getd(".@node_x"+.@to_ary[1]+"y"+.@to_ary[2]+"c[0]")+.@m); } /*else {*/ if( .@to_ary ) { //-------------------------------------------------------------------> Testing open node. "True: Test if better parent to current closed node." set .@tmp$, ".@node_x"+.@x+"y"+.@y; //---------------------------------------------> (".@node_x"+.@x+"y"+.@y) Temp string. copyarray .@cc_ary, getd(.@tmp$+"c[0]"), 6; //-------------------------------------> .@cc_ary = "Current closed array". (Parent to testing nodes.) .@mes$ = .@mes$+" On open list... Testing!"; if( (.@cc_ary[0] + .@m ) < .@to_ary[0] ) { //--------------------------------------> Challenge current node g plus distance to parent less than testing node g. //dispbottom "New Parent: "+.@x2+", "+.@y2; .@mes$ = .@mes$+" shorter route!"; setarray getd(.@tmp$+"c[0]"), //-----------------------------------------------> (".@node_x"+.@x+"y"+.@y+"c[0]") (.@cc_ary[0] + .@m ), .@x2, .@y2, //----------------------------------------> new g, new parent >Recalculate current closed node. ((.@cc_ary[0] + .@m ) + getd(".h_x"+.@x+"_y"+.@y)); //-----------------------> g + heuristic = new heuristic. killmonster "ama_dun01",strnpcinfo(0)+"::On"+.@x2+"-"+.@y2; monster "ama_dun01",.@x2,.@y2,"New Parent",1936,1,strnpcinfo(0)+"::On"+.@x2+"-"+.@y2; killmonster "ama_dun01",strnpcinfo(0)+"::On"+.@x+"-"+.@y; monster "ama_dun01",.@x,.@y,"New Child",1935,1,strnpcinfo(0)+"::On"+.@x+"-"+.@y; copyarray getd(".@node_x"+.@x2+"y"+.@y2+"c[0]"), .@to_ary[0], 6; //------------> Move testing open-list node to closed-list node. } else { .@mes$ = .@mes$+" Not shorter!"; } } else { //---------------------------------------------------------------------------> Testing open node. "False: Add it to the open-list!" .@mes$ = .@mes$+" Not on the open list... Adding!"; set .@g, getd(".@node_x"+.@x+"y"+.@y+"c[0]")+.@m; //-------------------------------> Testing open node g equals current closed node g plus distance to testing open node g. .@f = .@g + getd(".h_x"+.@x2+"_y"+.@y2); //----------------------------------------> Testing open node f equals g plus heuristic. setarray getd(.@a$), .@g, .@x, .@y, .@f, .@x2, .@y2; //----------------------------> Set testing open list node values. //dispbottom "Adding: "+ .@g+", "+.@x+", "+.@y+", "+.@f+", "+.@x2+", "+.@y2; monster "ama_dun01",.@x2,.@y2,"Added",1934,1,strnpcinfo(0)+"::On"+.@x2+"-"+.@y2; //if( getarraysize(getd("@open_list"+.@v+"$")) >= 32 ) //----------------------------> Is current operating open-list greater than or equal to thirty-two? // .@ar[getarraysize(.@ar)] = .@v++; //-------------------------------------------> Not enough room for child/parent store value in a new open-list. if( getarraysize(getd("@open_list"+.@v+"$")) >= 32 ) { while( getarraysize(getd("@open_list"+.@v+"$")) ) .@v++; .@ar[getarraysize(.@ar)] = .@v; } //debugmes "Adding: ("+.@f+"|"+.@x2+"|"+.@y2+") to @open_list"+.@v+"$ Len: "+getarraysize(getd("@open_list"+.@v+"$")); .@loops = callfunc("AddHeap", (.@f+"|"+.@x2+"|"+.@y2), getd("@open_list"+.@v+"$")); //--------> Adding open node to the heap/open-list. } } } else { .@mes$ = .@mes$+" On Closed List!"; } dispbottom .@mes$; if( .@v == 737/* && .@a == 7*/ ) end; .@a++; jump_zero ( .@a >= .@len ), LOOP4; //.@u = .@cu = .@w_temp = 0; .@u = 0; //-------------------------------------------------------------------------------------------> Current open-list. .@cu = 0; //-------------------------------------------------------------------------------------------> Challenged open-list. .@w_temp = 0; //----------------------------------------------------------------------------------------> Smallest f value. .@v_len2 = .@v_len; .@v_len = getarraysize(.@ar); //-------------------------------------------------------------------------> Size of condensed open-lists. if(.@v_len2 < (.@v_len-1)) { debugmes .@v+"Dropped Value! "+.@v_len2+"<"+(.@v_len-1); } while( .@u<.@v_len //---------------------------------------------------------------------------------> While testing list within open list range /*|| !.@v_len //------------------------------------------------------------------------------------> or open-list doesn't exist >Find shortest open-list f. ( Might not need last parts double check. ) && .@u<=.@v_len*/ ) { //----------------------------------------------------------------------------> and testing list less than length lists. .@cu = .@ar[.@u]; .@len2 = getarraysize(getd("@open_list"+.@cu+"$")); .@tmp = atoi(getd("@open_list"+.@cu+"$")); debugmes .@u+" OpenList Array "+.@ar[.@u]; if( .@tmp<.@w_temp || !.@w_temp ) { .@w_temp = .@tmp; .@w_len = .@len2; .@w_ptr = .@u; .@w = .@cu; } //dispbottom "Len: "+.@len2+" "+getarraysize(getd("@open_list"+.@u+"$"))+"| Temp: "+.@tmp+"| .@w: "+.@w+"| .@u: "+.@u; .@u++; } //dispbottom "Before: "+getarraysize(getd("@open_list"+.@w+"$")); explode .@array$, getd("@open_list"+.@w+"$"), "|"; copyarray .@temp[0], getd(".@node_x"+.@array$[1]+"y"+.@array$[2]+"o[0]"), 6; //if(!(.@w_len-1)) { dispbottom "Deleteing: "+.@ar[.@w_ptr]+" | Array Size: "+getarraysize(getd("@open_list"+.@w+"$"))+" | Array: "+getd("@open_list"+.@ar[.@w_ptr]+"$"); } callfunc "DelHeap", 0, getd("@open_list"+.@w+"$"), .@w_len; if( .@w_len==1 ) { deletearray .@ar[.@w_ptr],1; } if( !getd(".@node_x"+.@array$[1]+"y"+.@array$[2]+"c[0]") ) { if(.@temp) { viewpoint 2, .@x, .@y, /*(*/.@q/*+.@a)*/, 0xFF0000; .@x = .@temp[4]; .@y = .@temp[5]; copyarray getd(".@node_x"+.@x+"y"+.@y+"c[0]"), .@temp, 6; deletearray getd(".@node_x"+.@x+"y"+.@y+"o"); setarray .@temp, 0, 0, 0, 0, 0, 0; ////monster "ama_dun01",.@x,.@y,"Using",1934,1; } } set(.@a,0); if(.@x==.@e_x&&.@y==.@e_y) { dispbottom "We did it"; break; } //We've reached the end. //if(.@x==.@l_x&&.@y==.@l_y) { dispbottom "Can't be solved!"; end; } //This puzzle can't be solved. .@l_x = .@x; .@l_y = .@y; .@q++; if(.stop) end; if(!(.@q%1000)/*.@v2 != .@v*/ ) { .@v2 = .@v; //viewpoint 1, .@x, .@y, /*(*/.@q/*+.@a)*/, 0xFF0000; //dispbottom "Still Working: .@q="+.@q+" | @open_list"+.@v+"$ Len="+getarraysize(getd("@open_list"+.@v+"$"))+" | .@ar Size: "+getarraysize(.@ar)+" | Cords: "+.@x+", "+.@y; sleep2(1); } if( getarraysize(getd("@open_list"+.@v+"$")) > 32 ) end; //dispbottom "Still Working: .@q="+.@q+" | @open_list"+.@v+"$ Len="+getarraysize(getd("@open_list"+.@v+"$"))+" | .@ar Size: "+getarraysize(.@ar)+" | Cords: "+.@x+", "+.@y; } LOOP3: .@x2 = getd(".@node_x"+.@x+"y"+.@y+"c[1]"); .@y2 = getd(".@node_x"+.@x+"y"+.@y+"c[2]"); monster "ama_dun01",.@x2,.@y2,"Path",1934,1; viewpoint 1, .@x, .@y, .@ii++, 0x00FF00; if(.@p_len>=128) { .@j++; .@p_len=0; } setd ".@p_l"+.@j+"$["+.@p_len+"]", .@x2+"|"+.@y2; .@p_len++; .@x = .@x2; .@y = .@y2; if( .@x == .@s_x && .@y == .@s_y ) GOTO L_1; if( !.@x && !.@y ) end; GOTO LOOP3; L_1: while(.@t<=.@j/*getarraysize(getd(".@p_l"+.@t+"$"))*/) { if(.@t<.@j) { .@len=64; .@i_len=128; } else { .@i_len = getarraysize(getd(".@p_l"+.@t+"$")); .@len =.@i_len/2; } for(.@y = 0; .@y < .@len; .@y++) { .@temp$ = getd(".@p_l"+.@t+"$["+.@y+"]"); setd(".@p_l"+.@t+"$["+.@y+"]",getd(".@p_l"+.@t+"$["+(.@i_len-.@y-1)+"]")); setd(".@p_l"+.@t+"$["+(.@i_len-.@y-1)+"]",.@temp$); } .@t++; } dispbottom "This process took: "+(gettimetick(0)-.@time)+" ms"; Clear: while(.@cu<=.@v) { deletearray getd("@open_list"+.@cu+"$"); .@cu++; } if(.@clear){ dispbottom "Cache Cleared"; end; } .@gid = bg_monster(.@a,"ama_dun01",233,8,"--ja--",3999,strnpcinfo(0)+"::OnDeadMob"); getmapxy(.@map$,.@m_x,.@m_y,3,""+.@gid); sleep2(100); set(.@z,.@t-1); while(getarraysize(getd(".@p_l"+.@z+"$"))) { while(.@k<getarraysize(getd(".@p_l"+.@z+"$"))) { explode(.@array$,getd(".@p_l"+.@z+"$["+.@k+"]"),"|"); unitwalk(.@gid,atoi(.@array$),atoi(.@array$[1])); sleep2(500); .@k++; } .@k=0; set(.@z,.@z-1); } end; OnGoHome: .stop = 1; end; OnGoClear: .@clear = 1; goto Clear; OnGoStart: warp "ama_dun01",233,9; end; OnList: getmapxy(.@map$,.@x,.@y,0); if(checkcell(.@map$,.@x,.@y,cell_chkwall) || checkcell(.@map$,.@x,.@y,cell_chkcliff) || checkcell(.@map$,.@x,.@y,cell_chknopass) || checkcell(.@map$,.@x,.@y,cell_chknoreach)) { dispbottom "Failed"; } else dispbottom "Added"; end; OnInit: bindatcmd "@stop",strnpcinfo(0)+"::OnGoHome"; bindatcmd "@clear",strnpcinfo(0)+"::OnGoClear"; bindatcmd "@list",strnpcinfo(0)+"::OnList"; bindatcmd "@start",strnpcinfo(0)+"::OnGoStart"; setarray .@map_max, 240, 0; .e_x = 232; //End Pos .e_y = 144; //End Pos freeloop(1); set(.@time,gettimetick(0)); if(!.h_switch) { .@x = 0; .@y = 240; LOOP1: LOOP2: if(checkcell("ama_dun01",.@x,.@y,cell_chkwall) || checkcell("ama_dun01",.@x,.@y,cell_chkcliff) || checkcell("ama_dun01",.@x,.@y,cell_chknopass) || checkcell("ama_dun01",.@x,.@y,cell_chknoreach)) {} else setd(".h_x"+.@x+"_y"+.@y, (10*(abs([email protected]_x ) + abs([email protected]_y )))); jump_zero ((.@y--)<.@map_max[1]),LOOP2; .@y = 240; jump_zero (.@x++>.@map_max),LOOP1; npctalk "This process took: "+(gettimetick(0)-.@time)+" ms"; } else { .@x_d = abs(.@x2-.@e_x); .@y_d = abs(.@y2-.@e_y); if(.@x_d > .@y_d) .@h = 14*.@y_d + 10*(.@x_d-.@y_d); else .@h = 14*.@x_d + 10*(.@x_d-.@x_d); //.@x_d = abs(.@x2 - .@e_x); //.@y_d = abs(.@y2 - .@e_y); //.@h = /*.@m*/14 * max(.@x_d, .@y_d); } } function script AddLeaf { .@key = getarg(0,0); .@ptr = getarg(1,0); if(!getstrlen(@node$)) @node$ = getarg(0)+"||"; else if(getarg(0) < atoi(@node$[.@ptr])) { if(getarraysize(@node$)>=(2*.@ptr)+1) { if(@node$[(2*.@ptr)+1]!="") //charat(.@node$[.@ptr],strpos(.@node$[.@ptr],"|")+1) callfunc("AddLeaf",((2*.@ptr)+1)); else @node$[(2*.@ptr)+1] = getarg(0)+"||"; } else { @node$[(2*.@ptr)+1] = getarg(0)+"||"; } } else if(getarg(0) > atoi(@node$[.@ptr])) { if(getarraysize(@node$)>=(2*.@ptr)+2) { if(@node$[(2*.@ptr)+2]!="") //charat(.@node$[.@ptr],strpos(.@node$[.@ptr],"|")+1) callfunc("AddLeaf",((2*.@ptr)+2)); else @node$[(2*.@ptr)+2] = getarg(0)+"||"; } else { @node$[(2*.@ptr)+2] = getarg(0)+"||"; } } else { dispbottom "The key has already been added to the tree."; } } //AddHeap({<value>,<array>,<pointer>}); function script AddHeap { .@key = getarg(0,0); .@ke$ = getarg(0,0); .@ptr = getarg(2,getarraysize(getarg(1,@node$))); copyarray .@ar$, getarg(1,@node$), .@ptr; LOOP: .@loops++; ///if(.@ptr>64) return 1; if(.@ptr) { .@pnt = (.@ptr-1)>>1; } if( getarraysize(.@ar$) ) if( countstr("#"+implode(.@ar$,"#")+"#", "#"+.@ke$+"#", 0) > 1 ) { debugmes .@ke$+" exists in "+implode(.@ar$,"#")+" loops "+.@loops; } if(!/*getstrlen(*/getarraysize(.@ar$)/*)*/) { .@ar$ = .@ke$; } else if(atoi(.@ar$[.@pnt]) > .@key) { .@temp$ = .@ar$[.@pnt]; .@ar$[.@pnt] = .@ke$; .@ar$[.@ptr] = .@temp$; .@ptr = .@pnt; goto LOOP; } else if(getarraysize(.@ar$)<=.@ptr) { .@ar$[.@ptr] = .@ke$; } copyarray getarg(1,@node$), .@ar$, getarraysize(.@ar$); return .@loops; } function script DelHeap { .@ptr = getarg(0,0); .@len = getarg(2,getarraysize(getarg(1,@node$)))-1; if( .@len < 0 ) end; copyarray .@ar$, getarg(1,@node$), .@len+1; .@ar$[.@ptr] = .@ar$[.@len]; .@ar$[.@len] = ""; deletearray getelementofarray(getarg(1,@node$),.@len),1; LOOP: .@cn1 = (.@ptr<<1)+1; //.@cn1 = (.@ptr*2)+1; .@cn2 = .@cn1+1; .@ptn = atoi(.@ar$[.@ptr]); .@cd1 = atoi(.@ar$[.@cn1]); if(.@len>.@cn2) { .@cd2 = atoi(.@ar$[.@cn2]); if(.@cd1>.@cd2) { if(.@ptn>.@cd2) { .@temp$ = .@ar$[.@ptr]; .@ar$[.@ptr] = .@ar$[.@cn2]; .@ar$[.@cn2] = .@temp$; .@len = getarraysize(.@ar$); .@ptr = .@cn2; goto LOOP; } } else { if(.@ptn>.@cd1) { .@temp$ = .@ar$[.@ptr]; .@ar$[.@ptr] = .@ar$[.@cn1]; .@ar$[.@cn1] = .@temp$; .@len = getarraysize(.@ar$); .@ptr = .@cn1; goto LOOP; } } } else if(.@ptn>.@cd1&&.@len==2) { .@temp$ = .@ar$[.@ptr]; .@ar$[.@ptr] = .@ar$[.@cn1]; .@ar$[.@cn1] = .@temp$; } else if(!.@ptn&&.@len==2) { .@temp$ = .@ar$[.@ptr]; .@ar$[.@ptr] = .@ar$[.@cn1]; .@ar$[.@cn1] = .@temp$; } copyarray getarg(1,@node$), .@ar$, getarraysize(.@ar$); return; } function script PrintInOrder { .@ptr = getarg(0); if(getarraysize(@node$)) { if(getarraysize(@node$)>=(2*.@ptr)+1) { if(@node$[(2*.@ptr)+1]!="") callfunc("PrintInOrder",((2*.@ptr)+1)); } .@message = .@message + @node$[.@ptr]; if(getarraysize(@node$)>=(2*.@ptr)+2) { if(@node$[(2*.@ptr)+2]!="") callfunc("PrintInOrder",((2*.@ptr)+2)); } } else { dispbottom "The tree is empty."; } } function script test { copyarray .@array$, getarg(0), getarraysize(getarg(0)); for(.@a=0;.@a<getarraysize(getarg(0));.@a++) { //dispbottom ""+getelementofarray(getarg(0),.@a); dispbottom .@array$[.@a]; } //return; dispbottom "done"; } test_map,7,82,5 script AtoI-Test 100,{ /*freeloop(1); .@time=gettimetick(0); for(.@a=0;.@a<1000;.@a++) { .@b = atoi("100|32432|10"); //.@b = atoi("100#32432#10"); //.@b = atoi("100a32432a10"); } npctalk "Test 1 "+(gettimetick(0)-.@time)+"ms"; Sleep(100); .@time=gettimetick(0); for(.@a=0;.@a<1000;.@a++) { explode(.@a$,"100|32432|10","|"); //explode(.@a$,"100#32432#10","#"); //explode(.@a$,"100a32432a10","a"); } npctalk "Test 2 "+(gettimetick(0)-.@time)+"ms";*/ deletearray @node$; ///setarray .@keys$, "50", "76", "21", "4", "32", "64", "15", "52", "14", "100", "83", "2", "3", "70", "87", "80"; ///setarray .@keys, 410, 705, 732, 23, 195, 78, 452, 970, 804, 970; setarray .@keys$, "9212", "7387", "1821", "4979", "9241", "1309", "4870", "4946", "707", "3081", "2141", "2135", "5324", "9566", "9638", "8759", "8749", "5620", "8667", "7287", "8", "668", "4899", "3688", "5614", "2754", "8833", "8783", "1682", "2781", "2720", "7709", "2120", "306", "6410", "4590", "6040", "3933", "2124", "5542", "6361", "7499", "3610", "155", "35", "9936", "1935", "8725", "9049", "4406", "5905", "4539", "6843", "9243", "3569", "5038", "2712", "8041", "2181", "796", "9083", "3534", "891", "1687"; dispbottom "Len "+getarraysize(.@keys$); ///callfunc("test",.@keys$); debugmes implode(@node$,"#"); .@tick = gettimetick(0); for(.@a=0;.@a<getarraysize(.@keys$);.@a++) callfunc("AddHeap",(.@keys$[.@a]),.@node$); ///callfunc("PrintInOrder"); debugmes implode(.@node$,"#"); for(.@a=0;.@a<getarraysize(.@keys$);.@a++) { callfunc("DelHeap",0,.@node$); debugmes implode(.@node$,"#"); } .@tock = gettimetick(0); debugmes ( .@tick-.@tock )+"ms"; }
    1 point
  2. 1 point
  3. AEGIS Vs emulador con renewal. La experiencia renewal actualmente en AEGIS es completamente diferente a cualquier emulador del mercado. Aparte de que ellos aunque suene mal no buscan identificar a los latinos, ya que solo dan soporte exclusivamente para españa.
    1 point
  4. Kapitel 1: Alles hat einen Anfang 1.0 - Einführung in die Welt der Scripter (Vorwort) 1.1 - NPCs (Non-Playable-Character) 1.2 - Script Commands 1.3 - Befehle Teil 1 - Abläufe 1.4 - Variablen 1.5 - Operatoren 1.6 - If-Abfragen 1.7 - Labels 1.8 - Kommentare 1.9 - Befehle Teil 2 - Menüs und Eingaben Kapitel 2: Der Weg des Kriegers 2.0 - Noch ein weiter Weg 2.1 - Arrays 2.2 - Befehle Teil 3 - Die erste Quest 2.3 - Befehle Teil 4 - Effiziente und bessere Menüs 2.4 - SQL 2.5 - Verschiedene Arten von NPCs 2.6 - Schleifen 2.7 - Monster 2.8 - Events Kapitel 3: Die geheime Kunst der Mönche 3.0 - Willkommen im Orden 3.1 - RID 3.2 - Funktionen 3.3 - Dynamische Menüs 3.4 - Dynamische Shops 3.5 - Dynamische Arrays 3.x - Coming soon... Kapitel 1: Alles hat einen Anfang 1.0 - Einführung in die Welt der Scripter (Vorwort) Viele neue Scripts entstehen in der Ragnarok Community. Die internationale Community tut ihr bestes daran stetig neue Dinge zu entwickeln und das Leben in Ragnarok so wie wir es kennen zu erweitern und den Spaß zu vergrößern. Es gibt viele verschiedene Arten von Scripts. Mal sind es kleine Dinge, wie ein Kafra Shop oder auch was größeres, wie ein Quest System. Die Möglichkeiten sind unendlich. Ich vertrete die Meinung das Scripts das Herzstück jedes Servers sind. Sie sind die letzte Schnittstelle zu den Spielern und die Spieler sind es die damit kommunizieren. Umso wichtiger ist es das sie auch funktionieren und den Spielern neue Möglichkeiten bieten Ragnarok neu zu erleben. Ich möchte euch in diese wunderbare Welt des Scriptens einführen und euch zeigen das in jedem von euch ein Scripter stecken kann und das auch ihr euren Teil zu dieser tollen Community beitragen könnt. Wie wird das Guide ablaufen ? - Ich werde euch Schritt für Schritt durch die Thematik führen und euch so gut es geht alles erklären was ihr wissen müsst. Mit Beispielen vereinfache ich das ganze und erläutere anschließend alles. Gegebenfalls werde ich euch danach kleine Aufgaben stellen die ihr versucht zu lösen. Hier wirkt das Trial and Error Prinzip. Versuchen und Scheitern. Das ganze wiederholt ihr bis es funktioniert. Der Prozess des Lernens erfordert Fehler zu machen und aus diesen Fehlern lernen wir und dann machen wir es besser. Es wichtig das ihr viel übt und wiederholt um euch Dinge einzuprägen. 1.1 - NPCs (Non-Playable-Character) NPC, auch genannt Non-Playable-Character sind die Personen die in der Map verteilt stehen und die man als Spieler ansprechen kann. Jeder NPC hat ein Grundgerüst, welches ich euch hier zeige. Beispiel: prontera,156,212,7<tab>script<tab>Charlie<tab>811,{ } Erläuterung: Das ist unser Beispiel namens Charlie, so sieht das Grundgerüst für jeden NPC aus. Es definiert alle wichtigen Daten über den NPC. Auf welcher Map es sich befindet, wo es genau steht, wie es heißt und wie es aussieht. Gehen wir mal genauer drauf ein. prontera = Die Map auf der sich der NPC befindet 156 = Die X Koordinate auf der Map 212 = Die Y Koordinate auf der Map 7 = Ausrichtung des NPCs (Die Richtung in die der NPC schaut) script = Typ des NPCs (Es gibt verschiedene Typen von NPCs auf die ich noch eingehen werde) Charlie = Name des NPCs (Was der Spieler im Spiel sieht unter dem NPC) 811 = Aussehen des NPCs (Es werden IDs für das Aussehen verwendet) <tab> = Das sollte wohl klar sein. Es ist wichtig das ihr <tab> drückt und keine Leerzeichen verwendet, ansonsten funktioniert der Script nicht { } = Hier beginnt der Spaß, denn hier kommen später unsere Befehle und alles andere rein Map,X,Y: Wenn ihr wissen wollt wohin ihr euren NPC hinstellen sollt dann geht im Spiel auf die gewünschte Stelle und tippt folgendes ein: "/where". Hiermit erfahrt ihr auf welcher Map und X und Y Koordinate ihr euch befindet. Somit habt ihr schon so gut wie alles was ihr braucht. Ausrichtung des NPCs: [1][8][7] [2][ ][6] [3][4][5] An diesem Raster könnt ihr sehen welche Zahl für welche Blickrichtung steht. Mehr gibt es eigentlich dazu nicht zu sagen. Typ des NPCs: Es gibt wie schon gesagt verschiedene Arten von NPC Typen. Ich zeige euch die wichtigsten. script = Standard NPC Typ (Wird am häufigsten verwendet) shop = Shop NPC (wie der Name schon sagt handelt es sich hierbei um ein Shop) monster = Monster Spawn (Dieser Typ legt ein Spawn für Monster fest) warp = Warp Point (Ein Warp Punkt der euch zur gewünschten Map, X und Y Koordinate bringt) Name des NPCs: Den denkt ihr euch natürlich selbst aus. Es ist zu beachten das NPC Namen auch Leerzeichen enthalten dürfen. Maximal können 23 Zeichen für den Namen verwendet werden und jeder Name muss einzigartig sein. Der Server erlaubt keine doppelte Namen, da sonst Daten durcheinander kommen würden. (z.B. bei Event Labels) Aussehen des NPCs: Eine Liste der NPCs und deren IDs findet ihr z.B. hier: http://nn.nachtwolke.com/dev/npclist/ Hinweis: Haltet euch immer an das Beispiel, dann kann nichts schief gehen. Falls doch mal ein Fehler auftaucht, dann schaut nach ob ihr auch <tab> statt Leerzeichen verwendet habt und ob alle Kommas richtig sitzen. 1.2 - Script Commands Im Laufe der Zeit werde ich neue Befehle aufgreifen und ich kann euch natürlich nicht jeden Befehl ins Detail erklären, deswegen müsst ihr lernen die Wiki zu lesen. Dort findet ihr alle Script-Befehle bis in jedes Detail erklärt, sogar mit Beispielen. Das ist sehr wichtig. Ihr könnt euch nicht alle Befehle am Anfang merken, erst recht nicht wie alles funktioniert. Nutzt es als Nachschlagewerk und haltet euch nicht zurück. Die Wiki werdet ihr noch sehr oft verwenden müssen. Link: http://rathena.org/wiki/Category:Script_Command 1.3 - Befehle Teil 1 - Abläufe Hier beginnt der ganze Spaß. Ihr werdet nun euren ersten sprechenden NPC erstellen. Beispiel: prontera,156,212,7 script Charlie 811,{ mes "[Charlie]"; mes "Hallo ! Mein Name ist Charlie."; next; mes "[Charlie]"; mes "Ich heiße euch willkommen!"; close; } Erläuterung: Sobald ihr den NPC anklickt wird der Script zwischen den { } ausgeführt. Das ist der sogenannte Script-Block. Dieser enthält den kompletten Script des NPCs. Ich erläutere euch nun die Befehle die ich hier verwendet habe. mes "<message>"; Öffnet ein Fenster mit dem folgenden Text "<message>". Die beiden "" beinhalten den Text der ausgegeben werden soll und mit ; beenden wir den Befehl. Ein mes steht für eine Zeile. Bedeutet, wenn ihr eine neue Zeile anfangen wollt verwendet ein weiteres mes. Wenn ihr in der Wiki schaut werdet ihr verschiedene Varianten finden. Link: http://rathena.org/wiki/Mes next; Zeigt euch ein Button am unteren Rand des Fensters an. Bedeutet das Script pausiert und wartet darauf bis ihr "Next" klickt. Tut ihr das wird das Fenster gesäubert und ihr könnt es wieder neu füllen. Somit könnt ihr eure Texte strukturieren und leserlicher machen, (auch segmentieren genannt), und dem Spieler Zeit geben Stück für Stück den Text zu lesen. Stellt euch zum Beispiel eine Unterhaltung mit dem NPC und dem Spieler vor, sieht besser aus und ist Spieler-freundlicher. Link: http://rathena.org/wiki/Next close; Dieser Befehl zeigt euch ein Close Button am unteren Rand des Fensters an. Wenn ihr es klickt wird das Fenster geschlossen und der Script beendet. Wenn ihr nach diesem Befehl noch mehr Befehle schreibt werden diese nicht ausgeführt, deswegen wird close ausschließlich nach mes und next verwendet. Link: http://rathena.org/wiki/Close Der Server arbeitet Schritt für Schritt jede Zeile ab. Stellt euch vor ihr gibt einem Kleinkind vor was es zu tun hat. Gar nicht mal so schwer oder ? Lernaufgabe: Erstelle ein NPC namens Harald, welches dem Spieler sagt das er ihn in Ruhe lassen soll. Danach wird das Script normal beendet. Wenn ihr wollt probiert es mit verschiedenen Namen und verschiedenen Texten und wenn ihr wollt auch an verschiedenen Orten. Ihr könnt Harald auch ein anderes Aussehen verpassen. Probiert alles aus und macht euch mit dem Grundgerüst und den Befehlen vertraut. Hinweis: Vergesst nicht das ; nach jedem Befehl zu verwenden. Ihr werdet es am Anfang sehr oft vergessen. Prägt es euch also schon früh ein! Das ; wird verwendet um ein Befehl zu beenden. 1.4 - Variablen Beim Scripten wird der Punkt kommen wo ihr Variablen verwenden müsst. In diesen könnt ihr Informationen speichern, sie aufrufen und verarbeiten. Ich werde euch die verschiedenen Arten von Variablen und deren Limitationen zeigen. Integer: Sind sogenannte Ganzzahlen z.B. (0, 1, 2, 3, 592, -235, -2, etc.) Zu beachten ist das wenn ihr Kommazahlen verwendet, diese einfach geschnitten werden. Bedeutet wenn ihr 5.6 eintippt. Dann wird der Server nur die 5 benutzen und nicht das was hinter dem Komma steht. Später ist das wichtig zu beachten wenn ihr rechnet und Irgendetwas zum Beispiel durch 2 teilen wollt. Behaltet dies im Hinterkopf. String: Sind sogenannte Zeichenketten z.B.: "Hallo", "Dies ist eine Botschaft" oder auch Buchstaben wie "a" und "b". Beinhaltet alle euch bekannten Zeichen von A bis Z und Wörter, Sätze, Sonderzeichen und auch Zahlen. (Mit den Zahlen kann man dann aber nicht rechnen!) Hier ist zu beachten das Strings immer in "" geschrieben werden müssen, ansonsten werden diese nicht erkannt und es gibt Fehlermeldungen. Hier nun die verschiedenen Typen die man in der Athena Scripting Sprache festlegen kann: variablenname = Eine permanente Charakter basierende Variable @variablenname = Eine temporäre Charakter basierende Variable .variablenname = Eine permanente NPC Variable .@variablenname = Eine temporäre NPC Variable $variablenname = Eine globale permanente Variable $@variablenname = eine globale temporäre Variable #variablenname = eine permanente Account basierende Variable Ein $ and das Ende einer Variable liefert eine String Variable die man z.B. für die Input funktion gebrauchen kann. z.B.: @var$ <--- Eine temporäre String Variable mit dem Namen var. Temporär bedeutet das die Variable gelöscht wird sobald der Server resetted wird. Permanent bedeutet das die Variable bleibt selbst wenn der Server resetted wird. Global bedeutet das sie für den Server gilt und nicht nur für den Charakter oder Account. Account bassierend bedeutet das sie für den Account gesetzt wird. (Nützlich wenn man Quests auf nur 1x pro Account reduziern will) Bestimmt wollt ihr nun wissen wie man Variablen benutzt. Dafür brauchen wir den Befehl "set". Wie man ihn benutzt und in ein Script einbaut zeige ich euch jetzt. Beispiel: prontera,156,212,7 script Charlie 811,{ mes "[Charlie]"; mes "Hallo ! Mein Name ist Charlie."; next; mes "[Charlie]"; mes "Ich heiße euch willkommen!"; set @geredet, 1; close; } Erläuterung: Dies ist unser Beispiel von vorhin, aber etwas ist anders. Wir haben eine temporäre Charakter Variable namens "geredet" erstellt und eine 1 eingespeichert. Nun könnten wir am Anfang abfragen ob die Variable auf 1 gesetzt ist und wenn ja dann würde statt diesem Text ein ganz anderer Text erscheinen. Dafür brauchen wir die sogenannten If-Abfragen, zu denen wir schon bald kommen werden. set; Speichert einen Wert in eine Variable. Ist die Variable nicht vorhanden wird sie erstellt. Ist sie jedoch schon vorhanden, wird der alte Wert mit dem neuen Wert überschrieben. Link: http://rathena.org/wiki/Set Wir können Variablen auch abrufen und diese in "mes" ausgeben lassen. Beispiel: prontera,156,212,7 script Charlie 811,{ mes "[Charlie]"; set @geredet, 1; mes "Die Variable ist auf " + @geredet + " gesetzt"; close; } Erläuterung: Um eine Variable aufzurufen reicht es einfach den Namen anzugeben. Das "+" ist ein Operator, aber dazu kommen wir gleich. Ihr seht, das ich die Variable mit dem Rest des Textes ganz einfach verbunden habe indem ich das "+" dazwischen geschrieben habe. Als hätte ich es zusammengerechnet. (In diesem Fall verbunden) 1.5 - Operatoren Ich behandle in diesem Thema zwei Arten von Operatoren. Die mathematischen und die logischen Operatoren. Bei den logischen Operatoren gibt es nochmal zwei verschiedene Arten, unzwar die logischen Vergleiche und die logischen Verknüpfungen. mathematische Operatoren: + Addiert Zahlen - Subtrahiert Zahlen * Multipliziert Zahlen / Dividiert Zahlen (Hinweis: Nicht vergessen, bei einem Ergebnis von z.B 5.6 wird 5 rauskommen, da der Server nur Ganzzahlen verarbeitet) % Rest einer Division, z.B.: 7%2 = 1 Diese Operatoren sind ausschließlich für Integer zu verwenden. Die einzige Ausnahme ist "+", wie im Beispiel vorhin kann man damit Variablen mit Texten oder sogar Texte mit Texten verbinden. logische Operatoren (Vergleiche): == Trifft zu wenn beide Seiten gleich sind. [ 2==2 (wahr) 2==1 (falsch) ] != Trifft zu wenn beide Seiten nicht gleich sind. [ 1==1 (falsch) 2==1 (wahr) ] >= Trifft zu wenn der erste Wert größer oder gleich ist als der zweite Wert. [ 2>=2 (wahr) 3>=2 (wahr) 1>=2 (falsch) ] <= Trifft zu wenn der erste Wert kleiner oder gleich ist als der zweite Wert. [ 1<=2 (wahr) 1<=1 (wahr) 2<=1 (falsch) ] > Trifft zu wenn der erste Wert größer ist als der zweite Wert. [ 2>1 (wahr) 1>2 (falsch) ] < Trifft zu wenn der erste Wert kleiner ist als der zweite Wert. [ 1<2 (wahr) 2<1 (falsch) ] logische Operatoren (Verknüpfungen): && UND || ODER ! NICHT Diese Operatoren werden einzig und allein für If-Abfragen verwendet. 1.6 - If-Abfragen Jetzt wird es spannender. Nachdem wir gelernt haben was Variablen und Operatoren sind kommen wir nun zu den If-Abfragen. Hier werden wir sowohl variablen als auch logische Operatoren verwenden. Zudem lassen sich auch Funktionen mit Rückgabewerten verwenden, jedoch behandeln wir diese erst später. if; Es handelt sich dabei um eine logische Abfrage. Dabei werden Werte mit Hilfe von logischen Operatoren abgeglichen und auf ihre Wahrheit oder Falschheit überprüft. Je nach Resultat wird der darauf folgende Codeblock ausgeführt oder nicht. Link: https://rathena.org/wiki/If Beispiel: prontera,156,212,7 script Charlie 811,{ if(@geredet == 1) { mes "[Charlie]"; mes "Habe ich dir meinen Namen nicht schon verraten ?"; next; mes "[Charlie]"; mes "Na los, verschwinde endlich!"; close; } else { mes "[Charlie]"; mes "Hallo ! Mein Name ist Charlie."; next; mes "[Charlie]"; mes "Ich heiße euch willkommen!"; set @geredet, 1; close; } } Erläuterung: Wie ihr sehen könnt ist am Anfang von unserem netten Kerl Charlie eine If-Abfrage. Im Grunde wird überprüft ob die Variable "@geredet" auf 1 gesetzt ist, wenn diese Aussage WAHR ist, wird der Codeblock darunter zwischen den geschweiften Klammern ausgeführt. Danach kommt ein "else" welches auf Deutsch "ansonsten" bedeutet. Im Klartext: Ansonsten wenn die Aussage NICHT WAHR, also UNWAHR ist, führe den Codeblock unter "else" aus. Ein "else" ist kein muss, jedoch kommt es darauf an wie euer Script aufgebaut sein soll. In diesem Fall wollen wir entweder das eine ODER das andere ausgeben lassen. Nochmal: Wenn ihr den NPC das erste mal anspricht wird der Codeblock unter "else" ausgefuhrt weil @geredet noch nicht auf 1 gesetzt wurde. Das wird es dann dort. Beim zweiten mal Ansprechen ist die Aussage WAHR und der Codeblock unter "if" wird ausgegeben. Stellt euch das wie eine Gabelung vor, entweder der eine oder der andere Weg. Mehrere Verzweigungen: Es ist auch möglich mehrere If Abfragen zu verketten mit dem "else if" befehl, statt eines "else" benutzt ihr "else if"" und macht so noch eine abfrage. Die letzte wird dann ein "else" falls keine der vorherigen Abfragen zu trifft. Ergänzung: Es ist möglich alle Arten von Variablen miteinander zu vergleichen solange diese den selben Datentypen haben, heißt: string mit string vergleichen. Int mit Int vergleichen und so weiter. Ansonsten erhaltet ihr nur Fehler. Liest euch zudem unbedingt die Wiki Seite von if durch, damit ihr es besser versteht. 1.7 - Labels Labels werden heutzutage so gut wie kaum noch verwendet. Man bezeichnet es als unsauber. Es kann in einigen Situationen jedoch hilfreich sein und sollte niemals ganz vergessen werden. Wir werden dafür ein neuen Befehl benötigen den ich euch zeigen werde. goto <label>; Mit "goto" kann man an ein label springen. Heißt man springt an eine bestimmte Zeile im Script wo euer Label steht. Für mehr Informationen besucht die Wiki Seite. Link: https://rathena.org/wiki/Goto Beispiel: prontera,156,212,7 script Charlie 811,{ if(@geredet == 1) { goto L_geredet; } mes "[Charlie]"; mes "Hallo ! Mein Name ist Charlie."; next; mes "[Charlie]"; mes "Ich heiße euch willkommen!"; set @geredet, 1; close; L_geredet: mes "[Charlie]"; mes "Habe ich dir meinen Namen nicht schon verraten ?"; next; mes "[Charlie]"; mes "Na los, verschwinde endlich!"; close; } Erläuterung: Kommt euch das bekannt vor ? Genau es ähnelt dem "if" und "else" Beispiel. Statt das wir ein "else" verwenden, springen wir zur Zeile wo "L_geredet:" steht. "goto" erlaubt uns quasi einfach hin und her zu springen und von dort aus läuft der Script ganz normal weiter nach unten. Man kann mit dieser Methode auch aus Schleifen springen nachdem ein gewünschter Zustand erreicht wurde. Die Möglichkeiten sind unendlich. Lernaufgabe: Probiert euch mal selbst daran und baut ein paar Labels in euer Script und versucht hin und her zu springen. 1.8 - Kommentare Eines der nützlichsten Werkzeuge in der Informatik. Auch wenn sie selbst kein Einfluss auf eueren Script haben, werden sie dazu verwendet euch das Leben leichter zu machen. Wie der Name schon sagt sind es Kommentare. Sie dienen euch dazu Notizen im Script zu machen oder euren Script zu erklären und leserlicher zu machen und haben dabei kein Einfluss auf den Script selbst. Beispiel: prontera,156,212,7 script Charlie 811,{ //Hier frage ich ab ob die Variable @geredet auf 1 gestellt ist if(@geredet == 1) { goto L_geredet; //Wenn ja springe ich zum Label L_geredet } //Diese Stelle wird nur ausgeführt wenn wir nicht zu L_geredet gesprungen sind und die If-Abfrage UNWAHR war. mes "[Charlie]"; mes "Hallo ! Mein Name ist Charlie."; next; mes "[Charlie]"; mes "Ich heiße euch willkommen!"; set @geredet, 1; close; //Hier steht das Label. Man kann es sich als eine Art Checkpoint vorstellen an den man springen kann. L_geredet: mes "[Charlie]"; mes "Habe ich dir meinen Namen nicht schon verraten ?"; next; mes "[Charlie]"; mes "Na los, verschwinde endlich!"; close; } Erläuterung: Wie ihr sehen könnt beginnt man ein Kommentar mit "//" Damit hat die Zeile kein Einfluss mehr und steht nur als Text da für euch. Sehr hilfreich also nutzt es auch ! Im Laufe der Zeit lernt ihr sparsam aber effizient damit umzugehen. Ihr wollt euren Script damit ja nicht zukleistern. 1.9 - Befehle Teil 2 - Menüs und Eingaben - coming soon... _____________________________________________________________________________________ Dieses Guide basiert auf dem veralteten Guide aus 2007 welches erstmalig auf eAthena veröffentlich wurde. Ich selbst habe durch diesen Guide scripten gelernt. Ich habe dieses Werk als Grundlage für meinen Guide genommen. Die Struktur ist ähnlich oder wurde verändert, der Inhalt jedoch ist von mir verfasst und basiert auf der aktuellen rAthena Wiki. Link: Klick mich
    1 point
  5. Official Item Package commit: 51074a0 First, I don't understand why these package aren't implemented although rA has item group for long time (and beat me, no one mention about this?) Finally after doing 'stupid' manual parsing from Aegis ItemPackage database, I make other 'stupid' things: New script command: getgroupitem <itemgroup_id>; Modified IG_ structure for item_group database files: GroupID,ItemID,Rate{,Amount,Random,isAnnounced,Duration,isNamed,isBound} Added db file: db/re/item_package_db.txt Added doc file of explanation of how to use getgroupitem script and Item group database files: doc/item_group.txt Modified 2 script commands, see the explanation later. Basically, some item on IG group doesn't need to give player random and 'must' item, which can be done by getitem or rentitem script. Like or not, some items must has the player's name when it comes out from the box! Actually it can be done if I modify the getitem and rentitem, add an optional param as 'flag' for some items. But, the first optional param for getitem and rentitem is being used for 'char_id'. So I skip this idea and use getgroupitem script although the item that player will get only 1. Also, you will notice that some IG_ aren't used for certain items, I put comment /*getitemgroup();*/ getitem/rentitem ...; I made some as comment, because maybe one day user needs to add some random item from those IGs instead by using getitem/rentitem script. Then, what are the purpose new params for item group? Actually you can read some, here doc/item_group.txt I keep the IG format, to make the previous and new item group database (on db/re/item_package.txt) can be used by getrandgroupitem and getgroupitem script. Example, for IG_BlueBox although it doesn't have Amount, Random, isAnnounced, Duration, isNamed, isBound values, you still can use it by getgroupitem(IG_BlueBox); The item amount is adjusted to 1 (by default, not defined or 0 will be 1). But when you give the value for those IG data, maybe you can make player get 5 Oridecon from Old Blue Box, 10 Red Potion, etc. And for IGs from db/re/item_package.txt, you can use it by getrandgroupitem <group>,<quantity>{,sub_group}; too. Example, getrandgroupitem IG_Special_Box,1; Doesn't matter the amount that written at item_package.txt, player only will get 1 random item from random group 1. If you make it as getrandgroupitem IG_Special_Box,0; The amount is based on the 'amount' field. But those above, (I make) the getrandgroupitem ignores the rest fields (isAnnounced, Duration, isNamed, isBound), just like it used to be. Hmm.... So, it doesn't ignore the 'random' field? yes! Because with that commit, I modified 2 scripts: groupranditem group_num; to groupranditem <group_num>{,<sub_group>}; getrandgroupitem <group_id>,<quantity> to getrandgroupitem <group_id>,<quantity>{,<sub_group>} If you try to use getrandgroupitem for new item group structure which has 'Random' group field (the value between 0~5), without you give the 'sub_group' param, it always gives player the item with 'Random' group 1 (default). So you can decide which random group you want to pick. Example, look at IG_Low_Coin_Pocket, it has 4 random groups IG_Low_Coin_Pocket,Malang_Sp_Can,600,1,1,0,0,0 IG_Low_Coin_Pocket,Sapa_Feat_Cert,300,1,1,0,0,0 IG_Low_Coin_Pocket,Cgrade_Coin,100,1,1,0,0,0 IG_Low_Coin_Pocket,Malang_Sp_Can,600,1,2,0,0,0 IG_Low_Coin_Pocket,Mora_Coin,200,1,2,0,0,0 IG_Low_Coin_Pocket,Dgrade_Coin,200,1,2,0,0,0 IG_Low_Coin_Pocket,Malang_Sp_Can,500,1,3,0,0,0 IG_Low_Coin_Pocket,Manuk_Coin,300,1,3,0,0,0 IG_Low_Coin_Pocket,Egrade_Coin,200,1,3,0,0,0 IG_Low_Coin_Pocket,Malang_Sp_Can,500,1,4,0,0,0 IG_Low_Coin_Pocket,Splendide_Coin,300,1,4,0,0,0 IG_Low_Coin_Pocket,Egrade_Coin,200,1,4,0,0,0 If you use getrandgroupitem IG_Low_Coin_Pocket,x; the item that will appears only: Malang_Sp_Can, Sapa_Feat_Cert, or Cgrade_Coin. And if any item with group 0, it will be put into random group 1 (beside it has 'must' item) if you put the 'Rate' is more than 0. Like at this invalid bug report bugreport:8385, the player always get 2 items instead 1, why? He modified the original to IG_Pet_Egg_Scroll_Box1,Pet_Egg_Scroll1,100,1,0,0,0,1 Which makes the must item Pet_Egg_Scroll1 also as random item (random item with 100 probabilities without other rival, always be obtained). The players always get 2 items. Well, I think this is enough, I hope you all confuse! Thank you all
    1 point
  6. Latest Stable Client Latest Stable LUB Latest Stable Data Files/GRF Clean RO Folder PM Judas if you have any useful content to add, suggestions, or information to make this setup process much easier! Thanks!
    1 point
×
×
  • Create New...