/** * Handler to handle the gathering of implicitly existing * objects that require some skill to find, such as herbs. * Recognition (ie, knowing what it is once you've found it) may be * added later.<p> * The data used for gathering comes from two places: the handler's * database of gatherable items, and the room's local information.<p> * The handler's database contains a class entry for each gatherable:<br> * <dl> * <dt> skill (string) * <dd> The skill needed to find the item. * <dt> difficulty (int) * <dd> The taskmaster difficulty. * <dt> upper (int) * <dd> The taskmaster "upper" parameter. * <dt> extra (mixed) * <dd> The taskmaster "extra" parameter. * <dt> season (string *) * <dd> The seasons during which the gatherable is available (eg, plants). * If this is unset, the default is all seasons. * Note that, currently, it is the same season everywhere on the Disc. * <dt> quant (int or function pointer returning an int) * <dd> The quantity that will be gathered. The function pointer is * passed three parameters: the room, the player, and the name of the * gathered item. This allows, for example, a function to be called * on the room to calculate the quantity, such as: * <pre><br> * <code>(: $1->room_func($2, $3) :)</code> * </pre> * <dt> ob (string) * <dd> The pathname of the object to be created. If the object is * continuous, the <i>amount</i> of ob is set to <i>quant</i>; otherwise, * <i>quant</i> copies of the object are cloned. * </dl><p> * The room's local information is set when the gatherable is added * via add_item(), and consists of:<p> * <dl> * <dt> item name (string or function pointer returning a string) * <dd> The name that will be used to look up the gatherable in the * handler's database. The function pointer is passed two parameters * when evaluated: the room, and the player. * <dt> scarcity (int or function pointer returning an int) * <dd> The percent chance of finding any quantity of the gatherable. * This is an additional * constraint on finding the gatherable, in addition to any skill * requirements and quantity calculations. A scarcity of 100 (the default) * indicates no scarcity constraint. A scarcity of 0 means that the * gatherable will never be found. * </dl> * @author Jeremy */ #include <weather.h> #include <tasks.h> #define INIT_FILE "/obj/gatherables/handler.dat" class item_data { string skill; // skill needed to find this item int difficulty; // taskmaster difficulty int upper; // taskmaster "upper" parameter mixed extra; // taskmaster "extra" parameter string *season; // available season(s) mixed quant; // quantity (int or (int)(:<code>:)) string ob; // filename of object to be created } mapping items = ([ ]); void create() { seteuid("/secure/master"->creator_file(file_name(this_object()))); items = "/handlers/data"->compile_data(({ INIT_FILE })); } /* create() */ /** * This method will return an array of the information associated with * the item. The array consists of: * <pre> * ({ * skill, // skill needed to find this item (string) * difficulty, // taskmaster difficulty (int) * upper, // taskmaster "upper" parameter (int) * extra, // taskmaster "extra" parameter (mixed) * season, // available season(s) (string *) * quant, // quantity (int or (int)(:\<code\>:)) (mixed) * ob // filename of object to be created (string) * }) * </pre> * @return the item array as detailed above. * @param name the name of the item to query * @see add_item() */ mixed query_item( string name ) { class item_data h; if (!(items[name])) { return 0; } h = (class item_data)items[name]; return ({ h->skill, h->difficulty, h->upper, h->extra, h->season, h->quant, h->ob }); } /* query_item() */ /** * This method adds an item into the current list of gatherable items. * @param name the name of the item to add * @param skill skill needed to find this item * @param diff taskmaster difficulty * @param upper taskmaster "upper" parameter * @param extra taskmaster "extra" parameter * @param season available season(s) * @param quant quantity (int or function pointer returning an int) * @param ob filename of object to be created * @see query_item() * @see gather_item() */ void add_item( string name, string skill, int diff, int upper, mixed extra, string *season, mixed quant, string ob ) { class item_data h; h = new( class item_data ); h->skill = skill; h->difficulty = diff; h->upper = upper; h->extra = extra; h->season = season; h->quant = quant; h->ob = ob; items[name] = h; } /* add_item() */ /** * This method returns all of the current gatherable items. It returns * this as a mapping of a class, so probably not overly useful except * for debugging. * @return mapping of a locally defined class * @see query_item() * @see add_item() */ mapping query_items() { return items; } /* query_items() */ /** * This method attempts to gather some items in the environment of * the specified player. * @param word the item to try and gather * @param player the player doing the gathering * @return an array of gathered objects * @see query_item() * @see add_item() */ object *gather_item( string word, object player ) { object env; object *basket = ({ }), *hidden, item; class item_data h; mixed *local_data; string name; int i, q, j, l, m, result, scarcity; if (!objectp(player)) return basket; env = environment(player); if (!objectp(env)) return basket; // Find what items are defined in here hidden = match_objects_for_existence( word, ({ env }) ); if (!arrayp( hidden )) { return basket; } for (i = 0; i < sizeof( hidden ); i++) { // If it's an actual object lying here, gather it, too. Otherwise // we may never get to the gatherable due to plural problems. if (environment(hidden[i]) == env) { basket += ({ hidden[i] }); continue; } local_data = hidden[i]->query_gather(); for (j = 0; j < sizeof(local_data); j++) { name = 0; scarcity = 100; for (l = 0; l < sizeof(local_data[j]); l += 2) { // More modifiers can be added as they are needed switch (local_data[j][l]) { case "item name": case "item_name": name = evaluate(local_data[j][l+1], env, player); if (!stringp(name)) name = 0; break; case "scarcity": scarcity = evaluate(local_data[j][l+1], env, player, name); if (!intp(scarcity)) scarcity = 0; break; default: } } if (random(100) >= scarcity) continue; if (!items[name]) continue; h = items[ name ]; if (arrayp( h->season ) && sizeof( h->season )) if (member_array( WEATHER->query_season(), h->season ) == -1) continue; if (stringp( h->skill )) result = TASKER->attempt_task(h->difficulty, player->query_skill_bonus(h->skill), h->upper, h->extra); else result = SUCCEED; switch ( result ) { case FAIL: case BARF: continue; break; case AWARD: player->add_skill_level(h->skill, 1, 0); default: } q = evaluate(h->quant, env, player, name); if (!q || !intp(q)) continue; item = clone_object( h->ob ); #ifdef NO_DECAY item->set_decay_speed(0); #endif if (item->query_continuous()) { item->set_amount(q); basket += ({ item }); } else { basket += ({ item }); for (m = 1; m < q; m++) { basket += ({ clone_object( h->ob ) }); } } } /* for (j...) */ } /* for (i...) */ return (basket + ({ })); } /* gather_item() */