Heya,
I just wanted to add there that this is actually incorrect (unless there was a major update on rAthena I'm not aware of). The script engine does not allocate memory for the 0 to 4000 values in your example. Technically speaking, arrays are emulated and not actually arrays in the source. When you use ".array[4001]", the engine does the following:
".array" is a string that gets indexed. The string is given a unique number, say 9048. From then on, everytime the string ".array" is used, it will be refered to as 9048. This is called the id.
4001 is the index.
uid (id and index): Both of the values above combined as one (32bit for the id, 32bit for the index, making up 64bit for the uid).
The uid with its value is then stored in a big collection for the whole NPC script. This big collection also contains the values of other non-array variables such as ".temp = 20;". They are all stored in the same place. If you had written the variable as ".array_4001", it would have created a new unique value for the string such as 9049 and the index would have been 0. As you need to index the string everytime you create a new variable, using setd with a big amount of variables is usually not a good practice. Using .array[4001] is handled better source wise.
Quick note, but this is also why .@var = 5 is identical to .@var[0] = 5 and both would return the same value. They have the same uid.
What rAthena also does when you use an index greater than 0 is that it starts keeping track of the array keys (members). So say you used .array[4001], it will keep track that 4001 is a member of the array for the .array variable.
As for getarraysize(), it should be used very carefully and never in the condition of the for loop. getarraysize() does the following:
Checks if the .array value exists in the big collection. If not, adds 0 as a member of the array. (This is more of a hack, as it's impossible to know otherwise if [0] is part of the array or not.)
Go through all the members of the array and find the highest key, then does + 1.
So in your case, using getarraysize(.array) would indeed return 4002 as 4001 is the only member of the array. Using arrays instead of getd/setd would be much faster (and cleaner) in your script sample as a result:
prontera,155,181,5 script Card Buyer 757,{
mes "["+strnpcinfo(1)+"]";
mes "You have any card to sell ? <3";
next;
getinventorylist;
for (.@i = 0; .@i < @inventorylist_count; .@i++) {
.@price = .card[@inventorylist_id[.@i]];
if (.@price)
.@menu$ = .@menu$ + getitemname(@inventorylist_id[.@i]) + " ^FF0000"+F_InsertComma(.@price)+" Zeny^000000";
.@menu$ = .@menu$ + ":";
}
.@i = select(.@menu$) - 1;
clear;
.@price = .card[@inventorylist_id[.@i]];
mes "["+strnpcinfo(1)+"]";
mes "Sell "+getitemname(@inventorylist_id[.@i])+" for ^FF0000"+F_InsertComma(.@price)+" Zeny^000000?";
if (select("Confirm", "Cancel") == 1) {
delitem @inventorylist_id[.@i], 1;
Zeny += .@price;
clear;
mes "["+strnpcinfo(1)+"]";
mes "You have sold "+getitemname(@inventorylist_id[.@i])+" for ^FF0000"+F_InsertComma(.@price)+" Zeny^000000.";
}
close;
function AddCard {
.@price = getarg(0, 0);
.@getargcount = getargcount();
for (.@i = 1; .@i <= .@getargcount; .@i++)
.card[getarg(.@i, 0)] = .@price;
return;
}
OnInit:
// AddCard( <zeny>, <card_id>...);
AddCard( 10000, 4001, 4002, 4003, 4004);
AddCard(100000, 4011, 4012, 4013, 4014);
AddCard(500000, 4021, 4022, 4023, 4024, 4025);
AddCard(999999, 4031, 4032, 4033, 4034, 4035, 4036);
end;
}
Edit: This of course doesn't hold true if you would start iterating through the whole array with for (.@i = 0; .@i < getarraysize(.array); .@i++). This would give horrendous performance. We use the array there as a dictionary rather than a list.