Jump to content
  • 0

Scripting FAQ/Tips/Tricks


AnnieRuru

Question


  • Group:  Members
  • Topic Count:  18
  • Topics Per Day:  0.00
  • Content Count:  2044
  • Reputation:   682
  • Joined:  10/09/12
  • Last Seen:  

I make a continuation of this topic
this topic mainly concern about unpopular but useful scripting techniques ...
should wiki this up someday
 


 


Randomize item reward

 

  • Method 1: use F_Rand function.
  • Method 2: use temporary variables.
  • Method 3: use array.
     

 

Method 1: use F_Rand function

 

The function:

F_Rand can be found in our Git repository, Global Function

This function is indeed to be use for randomize a selection.

Usage:
       callfunc( "F_Rand", <argument no.1>, <argument no.2> ... )

       callfunc( "F_Rand", "Hi, how are you ?", "Hi, how do you do ?" )
       callfunc( "F_Rand", 1101, 1201, 1501 )
etc..

 

Sample:


prontera,153,180,5	script	test item reward#1	100,{
	getitem callfunc( "F_Rand", 501,502,503,504,505 ), 1;
	end;
}

 

 

Method 2: use temporary variables

 

Tips:

  1. Create a temporary variable with the total chance added up.
  2. Then utilizing chain of if...else-if condition sort them from lowest chance to highest chances. The chance are added from previous conditions     --->  condition   1, 1+2, 1+2+3, 1+2+3+4, ...
  3. Use else for last statement

 

Sample:


prontera,155,180,5	script	test item reward#2	100,{
	.@rand = rand( 1 + 2 + 3 + 4 + 5 + 5 + 10 + 15 ); // rand Total => 45
	if ( .@rand < 1 ) // 1/45 chance getting 10 knifes
		getitem 1201, 10;
	else if ( .@rand < 1+2 ) // 2/45 chance getting 5 knifes
		getitem 1201, 5;
	else if ( .@rand < 1+2+3 ) // 3/45 chance getting 2 knifes
		getitem 1201, 2;
	else if ( .@rand < 1+2+3+4 ) // 4/45 chance getting 1 knifes
		getitem 1201, 1;
	else if ( .@rand < 1+2+3+4+5 ) // 5/45 chance getting 10 red pots
		getitem 501, 10;
	else if ( .@rand < 1+2+3+4+5+5 ) // 5/45 chance getting 5 red pots
		getitem 501, 5;
	else if ( .@rand < 1+2+3+4+5+5+10 ) // 10/45 chance getting 2 red pots
		getitem 501, 2;
	// else if ( .@rand < 1+2+3+4+5+5+10+15 ) // use else for last statement
	else // 15/45 chance getting 1 red pot
		getitem 501, 1;
	end;
}

 

Method 3: use array

 

Tips:

  1. Create a preset of array (itemID array and chance array) under OnInit label. The total of itemID array and chance array should have same amount of indexes. Then total them with with another variable (.totalchance).
  2. For the chances : set a random value from .totalchance, then search through the .itemchance array. With every .itemchance value searched, .@rand variable getting deducted. When .@rand less than 0 the loop is breaked : you get an index(.@i) for itemID array.

    (Skorm edit: I'd like to add that in this example unless all item chances add-up to 100 .itemchance doesn't exactly represent a percent. In this example by Annie '3' is actually
    ~3.6% or 3/83. )

 

Sample:


prontera,157,180,5	script	test item_reward#3	100,{
	.@rand = rand(.totalchance);
	.@i = 0;
	while ( ( .@rand -= .itemchance[.@i] ) >= 0 ) .@i++;
	getitem .itemid[.@i], 1;
	end;
OnInit:
	setarray .itemid, 501,502,503,504,505,506,507,508,509;
	setarray .itemchance, 10,10,10,10,3,10,10,10,10;
	.@i = 0;
	while ( .itemid[.@i] ) {
		.totalchance += .itemchance[.@i];
		.@i++;
	}
	end;
}



sigh ... I seriously need someone to make the english better, my explanation always sux
any staff member here feels like can make this topic better, please do so

Edited by Skorm
  • Upvote 10
  • Love 1
Link to comment
Share on other sites

2 answers to this question

Recommended Posts

  • 0

  • Group:  Members
  • Topic Count:  18
  • Topics Per Day:  0.00
  • Content Count:  2044
  • Reputation:   682
  • Joined:  10/09/12
  • Last Seen:  

How to use *addrid script command properly

Method 1: Exploits its multi-concurrent run
-> use *addrid right before ending the script

addrid will run multiple instances equal to number of player attached, which, not entirely a bad thing
when use properly, as shown below, don't have to use loop

prontera,155,179,5	script	kickall	1_F_MARIA,{
	if ( getgmlevel() < 99 ) end;
	mes "I will kick all players after this dialog close";
	mes "Exclude: autotrader, GMs, wondering in town.";
	close2;
	addrid 0;
	if ( getgmlevel() >= 60 ) end; // don't kick GMs
	if ( checkvending() & 2 ) end; // shouldn't kick @autotraders
	if ( getmapflag( strcharinfo(3), mf_town ) ) end; // doesn't kick anyone in the town
	atcommand "@kick "+ strcharinfo(0);
	end;
}


Method 2: Get all the RID in an array
-> use donpcevent as calling a function, within that label, store the account IDs

the preferred method, this method is safe from running multiple instances

prontera,155,182,5	script	getallusers	1_F_MARIA,{
	donpcevent strnpcinfo(0)+"::OnGetAID"; // treat this as calling a function to get online player's account ID
	for ( .@i = 0; .@i < .c; ++.@i )
		announce (.@i +1)+". "+ rid2name(.aid[.@i]), bc_all;
	end;
OnGetAID:
	.c = 0;
	addrid 0;
	.aid[.c++] = getcharid(3);
	end;
}
-	script	getallmap	HIDDEN_NPC,{
	end;
OnTest:
	donpcevent strnpcinfo(0)+"::OnGetAID";
	for ( .@i = 0; .@i < .c; ++.@i )
		announce (.@i +1)+". "+ rid2name(.aid[.@i]), bc_all;
	end;
OnGetAID:
	.c = 0;
	addrid 5, 0, "payon"; // only attach to everyone inside payon map
	.aid[.c++] = getcharid(3);
	end;
OnInit:
	bindatcmd "test", strnpcinfo(0)+"::OnTest";
	end;
}
guild_vs2,0,0,0	script	getareausers	HIDDEN_NPC,{
	end;
OnTest:
	donpcevent strnpcinfo(0)+"::OnGetAID";
	for ( .@i = 0; .@i < .c; ++.@i )
		announce (.@i +1)+". "+ rid2name(.aid[.@i]), bc_all;
	end;
OnGetAID:
	.c = 0;
	addrid 4, 0, 46, 46, 53, 53; // attach everyone in the map 'guild_vs2' of (46,46,53,53) area
	.aid[.c++] = getcharid(3);
	end;
OnInit:
	bindatcmd "test2", strnpcinfo(0)+"::OnTest";
	end;
}


 

  • Upvote 1
  • Love 1
  • MVP 1
Link to comment
Share on other sites

  • 0

  • Group:  Forum Moderator
  • Topic Count:  33
  • Topics Per Day:  0.01
  • Content Count:  1268
  • Reputation:   381
  • Joined:  02/03/12
  • Last Seen:  

To Annie's post above she actually told me not to do this when I did it like 4 years ago...
What the heck and she doesn't even credit me here for maybe giving her some kind of subliminal inspiration whatever... :<
[Source] Hurry before she changes it. /gg


Anyways I just wanted to post a neat function I came up with for anybody who might want to use it.

DisplayPages Function:
Basically, it takes a bunch of options that you want to put into a menu and adds pages so the players can move through them easily.

///This function takes an array of strings and builds a menu players can navigate.
///Usage: DisplayPages(.@string_array${, .@page_size });
///Output: This function returns the selected item index from the given array.
function	script	DisplayPages	{
	.@page_size = getarg(1, 10);
	.@len = getarraysize(getarg(0));
	.@pages = .@len / .@page_size;
	.@pages -= .@len > .@page_size && .@len % .@page_size ? 0 : 1;
	
	do {
		copyarray .@copy$[0], getelementofarray(getarg(0), .@page_size * .@page), .@page_size;
		if( .@page < .@pages ) .@copy$[.@page_size] = "Next Page =>";
		if( .@page > 0 ) .@copy$[.@page_size +1] = "<= Previous Page";
		.@menu = select(implode(.@copy$,":"));
		if( .@menu == .@page_size +1 ) .@page++;
		else if( .@menu == .@page_size +2 ) .@page--;
		deletearray .@copy$;
	} while( .@menu > .@page_size );
	.@menu += .@page_size * .@page;
	return .@menu-1;
}

 

Example NPC:

prontera,146,188,4	script	Warper	97,{
		mes "[Warper]";
		mes "Select the map you want to warp to.";
		next;
		
		setarray .@maps$, "prontera", "morocc", "payon", "geffen", "izlude", "jawaii", "dewata", "eclage", "moscovia", "ayothaya", "lighthalzen", "alberta", "aldebaran", "xmas", "comodo", "hugel", "rachel", "veins", "pvp_n_1-5", "pvp_n_1-4";
		.@selection = DisplayPages(.@maps$, 5);
		warp .@maps$[.@selection], 0, 0;
		end;
}

 

Edited by Skorm
  • Upvote 3
  • Love 2
Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
×
×
  • Create New...