Skip to content

Commit

Permalink
Merge pull request #3319 from jasonch35/getmobdrops-refactor
Browse files Browse the repository at this point in the history
`getmobdrops` refactor
  • Loading branch information
MishimaHaruna authored Oct 26, 2024
2 parents 84da0df + e0fa6d8 commit 3056bce
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 56 deletions.
47 changes: 9 additions & 38 deletions doc/script_commands.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4364,54 +4364,25 @@ Example:

---------------------------------------

*getmobdrops(<mob id>)
*getmobdrops(<mob_id>, <item_id_array>{, <drop_rate_array>});

This command will find all drops of the specified mob and return the item
IDs and drop percentages into arrays of temporary global variables.
getmobdrops() returns true if successful and false if the mob ID doesn't
exist.

Upon executing this,

$@MobDrop_item[] is a global temporary number array which contains the
item IDs of the monster's drops.

$@MobDrop_rate[] is a global temporary number array which contains the
drop percentages of each item. (1 = .01%)

$@MobDrop_count is the number of item drops found.

Be sure to use $@MobDrop_count to go through the arrays, and not
'getarraysize', because the temporary global arrays are not cleared
between runs of 'getmobdrops'. If a mob with 7 item drops is looked up,
the arrays would have 7 elements. But if another mob is looked up and it
only has 5 item drops, the server will not clear the arrays for you,
overwriting the values instead. So in addition to returning the 5 item
drops, the 6th and 7th elements from the last call remain, and you will
get 5+2 item drops, of which the last 2 don't belong to the new mob.
$@MobDrop_count will always contain the correct number (5), unlike
getarraysize() which would return 7 in this case.
This command will find drops information of the specified <mob_id>, copy the
item ids on to <item_id_array> and drop rate on to <drop_rate_array> if provided.
Returns the number of items found. Will return 0 if <mob_id> is invalid.

Example:

// get a Mob ID from the user
input(.@mob_id);

if (getmobdrops(.@mob_id)) { // getmobdrops() returns true on success
// immediately copy global temporary variables into scope
// variables, since we don't know when getmobdrops() will get
// called again for another mob, overwriting your global temporary
// variables.
.@count = $@MobDrop_count;
copyarray(.@item[0], $@MobDrop_item[0], .@count);
copyarray(.@rate[0], $@MobDrop_rate[0], .@count);

.@count = getmobdrops(.@mob_id, .@item, .@rate);

if (.@count == 0) {
mes("No drops found.");
} else {
mes(getmonsterinfo(.@mob_id, MOB_NAME) + " - " + .@count + " drops found:");
for (.@i = 0; .@i < .@count; ++.@i) {
mes(.@item[.@i] + " (" + getitemname(.@item[.@i]) + ") " + .@rate[.@i]/100 + ((.@rate[.@i]%100 < 10) ? ".0":".") + .@rate[.@i]%100 + "%");
}
} else {
mes("Unknown monster ID.");
}
close();

Expand Down
87 changes: 69 additions & 18 deletions src/map/script.c
Original file line number Diff line number Diff line change
Expand Up @@ -12284,36 +12284,87 @@ static BUILDIN(monster)
*------------------------------------------*/
static BUILDIN(getmobdrops)
{
int class_ = script_getnum(st,2);
int i, j = 0;
struct mob_db *monster;
struct map_session_data *sd = NULL;
int mob_id = script_getnum(st, 2);
struct mob_db *monster = NULL;
struct script_data *data1 = script_getdata(st, 3);
struct script_data *data2 = NULL;
const char *varname1 = NULL;
const char *varname2 = NULL;
int varid1 = 0;
int varid2 = 0;
int num = 0;

if( !mob->db_checkid(class_) )
{
if (!data_isreference(data1) || reference_toconstant(data1)) {
ShowError("buildin_getmobdrops: Target argument must be a variable\n");
script->reportdata(data1);
st->state = END;
return false;
}

varname1 = reference_getname(data1);
varid1 = reference_getid(data1);

if (!is_int_variable(varname1)) {
ShowError("buildin_getmobdrops: Target argument must be an integer variable\n");
script->reportdata(data1);
st->state = END;
return false;
}

if (script_hasdata(st, 4)) {
data2 = script_getdata(st, 4);

if (!data_isreference(data2) || reference_toconstant(data2)) {
ShowError("buildin_getmobdrops: Target argument must be a variable\n");
script->reportdata(data1);
st->state = END;
return false;
}

varname2 = reference_getname(data2);
varid2 = reference_getid(data2);

if (data2 == NULL || !is_int_variable(varname2)) {
ShowError("buildin_getmobdrops: 2nd target argument must be an integer variable\n");
script->reportdata(data2);
st->state = END;
return false;
}
}

if (not_server_variable(*varname1) || (data2 != NULL && not_server_variable(*varname2))) {
sd = script->rid2sd(st);
if (sd == NULL) {
script_pushint(st, 0);
return true; // player variable but no player attached
}
}

monster = mob->db(mob_id);

if (!mob->db_checkid(mob_id) || monster == NULL) {
script_pushint(st, 0);
return true;
}

monster = mob->db(class_);

for( i = 0; i < MAX_MOB_DROP; i++ )
{
if( monster->dropitem[i].nameid < 1 )
for (int i = 0; i < MAX_MOB_DROP; i++) {
if (monster->dropitem[i].nameid < 1)
continue;
if( itemdb->exists(monster->dropitem[i].nameid) == NULL )
if (itemdb->exists(monster->dropitem[i].nameid) == NULL)
continue;

mapreg->setreg(reference_uid(script->add_variable("$@MobDrop_item"), j), monster->dropitem[i].nameid);
mapreg->setreg(reference_uid(script->add_variable("$@MobDrop_rate"), j), monster->dropitem[i].p);

j++;
script->set_reg(st, sd, reference_uid(varid1, num), varname1, (const void *)h64BPTRSIZE(monster->dropitem[i].nameid), reference_getref(data1));
if (data2 != NULL)
script->set_reg(st, sd, reference_uid(varid2, num), varname2, (const void *)h64BPTRSIZE(monster->dropitem[i].p), reference_getref(data2));
num++;
}

mapreg->setreg(script->add_variable("$@MobDrop_count"), j);
script_pushint(st, 1);
script_pushint(st, num);

return true;
}

/*==========================================
* Same as monster but randomize location in x0,x1,y0,y1 area
*------------------------------------------*/
Expand Down Expand Up @@ -29110,7 +29161,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(produce,"i"),
BUILDIN_DEF(cooking,"i"),
BUILDIN_DEF(monster,"siisii???"),
BUILDIN_DEF(getmobdrops,"i"),
BUILDIN_DEF(getmobdrops,"ii?"),
BUILDIN_DEF(areamonster,"siiiisii???"),
BUILDIN_DEF(killmonster,"ss?"),
BUILDIN_DEF(killmonsterall,"s?"),
Expand Down

0 comments on commit 3056bce

Please sign in to comment.