From 81c6a59d4b7643f9969461f1b92c34ad5fbcd95a Mon Sep 17 00:00:00 2001 From: jasonch Date: Wed, 11 Sep 2024 03:19:59 +0800 Subject: [PATCH 1/2] `getmobdrops` refactor Avoid the use of global temporary variables --- src/map/script.c | 87 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 18 deletions(-) diff --git a/src/map/script.c b/src/map/script.c index 8ecddd7fc43..490d54d57b9 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -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 *------------------------------------------*/ @@ -28996,7 +29047,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?"), From e0fa6d8f158f4962c043ea72079c6ed569c582eb Mon Sep 17 00:00:00 2001 From: jasonch Date: Wed, 11 Sep 2024 03:20:08 +0800 Subject: [PATCH 2/2] `getmobdrops` doc update --- doc/script_commands.txt | 47 ++++++++--------------------------------- 1 file changed, 9 insertions(+), 38 deletions(-) diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 1c4bb8aa3ab..675ad568f0a 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -4333,54 +4333,25 @@ Example: --------------------------------------- -*getmobdrops() +*getmobdrops(, {, }); -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 , copy the +item ids on to and drop rate on to if provided. +Returns the number of items found. Will return 0 if 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();