/** * The standard inheritable object for player-run shop counters. * * <p><b>Description</b></p> * The area behind the counter is the location of the sales log and the * cash register. It is also fitted as standard with a basic calculator * for those mathematically-challenged employees. * </p> * <p>The register holds the shop's float. Employees can put money in, * or get money from the register as with any other container, and all * additions and removals are logged. * </p> * <p>The shop's log allows employees to log a sale or purchase to verify * the actions they have taken. This allows managers and supervisors to * confirm that employees are not taking advantage of the shop as all stock * movements, register adjustments and log entries should match up. * </p> * * @example * #include "path.h" * * inherit "/std/shops/player_shop/counter"; * * void setup() * { * set_light(60); * set_office( PATH+ "office" ); * set_directions( "west", "south", "east" ); * * set_short( "behind the counter of Tarnach's shop" ); * set_long( "This is the area behind the counter of the Creel Springs " * "branch of Tarnach Fendertwin's Quality Consumables.\n" ); * add_exit( "south", PATH + "storeroom", "door" ); * add_exit( "east", PATH + "front", "path" ); * add_exit( "west", PATH + "office", "door" ); * } * * @see /include/player_shop.h * @see /std/shops/player_shop/office.c * @see /std/shops/player_shop/mgr_office.c * @see /std/shops/player_shop/storeroom.c * @see /std/shops/player_shop/shop_front.c * @see /std/shops/player_shop/shopkeeper.c * @author Ringo * @started 1st August 1999 */ inherit "/std/room/basic_room"; #include <player_shop.h> #include <money.h> private nosave mixed *_money; private nosave object _register = 0; private nosave string _save_file = "", _place = UNSET_STR, _office = "", _storeroom = "", _mgr_office = "", _shop_front = "", _store_dir = "", _office_dir = "", _shop_dir = ""; private nosave int _call_save = 0; int action(string); void add_money_ob(object); int adjust_register(string, int); string directions_to(string); private int do_calc(int,string,int); private int do_correction(mixed); private int do_log(mixed *); int query_register(); private void save_me(string); void save_register(int); protected void set_office(string); protected void set_directions(string, string, string); /** * @ignore yes */ void create() { do_setup++; ::create(); do_setup--; add_property("no burial", 1); add_property("determinate", ""); if (!do_setup) { this_object()->setup(); this_object()->reset(); } add_item("calculator", "A standard shop's calculator used to total " "up all those difficult prices. To use, see \"syntax calc\"."); add_help_file("player_shop_counter"); } /* create() */ /** * @ignore yes */ void init() { ::init(); if (!_office || _office == "") return; this_player()->command_override((: action :)); add_command("calc", "<number> {+|-|*|/} <number>", (: do_calc($4[0],$4[1],$4[2]) :)); if (_office->query_employee(this_player()->query_name()) || this_player()->query_creator()) { add_command("log", "shop {bought|sold} <number> <string'item(s)'> for <word'amount'>", (: do_log($4) :)); add_command("correction", "shop {bought|sold} <number> <string'item(s)'> for <word'amount'>", (: do_correction($4) :)); } } /* init() */ /** * @ignore yes * Disallow non-employees access to the register * @param str the action to intercept */ int action(string str) { string st1; if (_office->query_employee(this_player()->query_name()) || this_player()->query_creator()) return 0; sscanf(str,"%s %s",str,st1); if(str == "get" || str == "take") if (strsrch(st1, "register") != -1) { tell_object(this_player(), "You are not an active employee here!\n"); return 1; } return 0; } /* action() */ /** * @ignore yes * Put some money back into the register * @param money the money object to add */ void add_money_ob(object money) { if (previous_object() && previous_object() != find_object(_office)) { LOG_ERROR("counter.c", "add_money_ob()"); return; } if (!money) return; money->move( _register ); save_register(TRUE); } /* add_money_ob() */ /** * @ignore yes * Take some money from the register. * Used for transferring to bonus/profit accounts. * @param player the player adjusting the register * @param amount the amount to adjust by * @return the actual amount adjusted by */ int adjust_register(string player, int amount) { int value; object cash, change; if (previous_object() && previous_object() != find_object(_office)) { LOG_ERROR("counter.c", "adjust_register(" + player+","+amount+")"); return 0; } if (amount < 0) return 0; cash = present(MONEY_ALIAS, _register); if ( !cash ) return 0; _money = cash->query_money_array() + ({}); value = MONEY_HAND->query_total_value(_money, _place); if (value < amount) amount = value; change = MONEY_HAND->pay_amount_from( amount, cash, _place ); if (change) change->move( _register ); _office->shop_log(ACCOUNTS, player, "adjusted the register by "+ MONEY_HAND->money_value_string(amount, _place), UNPAID); save_register(TRUE); return amount; } /* adjust_register() */ /** * @ignore yes * Query the direction to another part of the shop. * This function is used by the npc shopkeeper to navigate around the shop. * @param place The full path to the destination. * @return The direction, or "here" if already there. */ string directions_to(string place) { if (place == _storeroom) return _store_dir; if (place == _office) return _office_dir; if (place == _shop_front) return _shop_dir; return "here"; } /* directions_to() */ /** * @ignore yes * Calculator */ private int do_calc(int a, string sign, int b) { int c = 0; string result = a+ " "+ sign+ " "+ b+ " = ", temp; switch (sign) { case "+" : result += sprintf("%d\n", a+b); break; case "-" : result += sprintf("%d\n", a-b); break; case "*" : result += sprintf("%d\n", a*b); break; case "/" : if (!b) { tell_object( this_player(), "Trying to divide by zero? Whatever next?\n"); return 1; } if (a % b) c = ((a%b) * 100)/b; temp = sprintf("%02d",c); result += sprintf("%d.%s\n", a/b, temp[0..1]); break; } tell_object(this_player(), result); add_succeeded_mess("$N use$s the calculator.\n"); return 1; } /* do_calc() */ /** * @ignore yes * Correct the shop's log */ private int do_correction(mixed *args) { _office->shop_log(LOG_ENTRY, this_player()->query_name(), "ERROR IN LOG - correct entry follows:", UNPAID); _office->shop_log(LOG_ENTRY, this_player()->query_name(), args[0]+ " "+ args[1]+ " "+ args[2]+ " for "+ args[3], UNPAID); add_succeeded_mess("$N make$s a correction in the transaction log book.\n"); return 1; } /* do_correction() */ /** * @ignore yes * Shop's log */ private int do_log(mixed *args) { _office->shop_log(LOG_ENTRY, this_player()->query_name(), args[0]+ " "+ args[1]+ " "+ args[2]+ " for "+ args[3], PAID); add_succeeded_mess("$N make$s an entry in the transaction log book.\n"); return 1; } /* do_log() */ /** * @ignore yes * Someone has died. * This function will automatically fire an employee if they have * killed someone whilst on duty. It will also make a note of anyone * who has killed an on-duty employee (including the npc shopkeeper). */ void event_death(object k, object *o, object k2, string r, string k3) { _office->event_death(k, o, k2, r, k3); } /* event_death() */ /** * @ignore yes * Someone has entered the room. * This function will automatically fire an employee if they have * teleported to this room. */ void event_enter(object ob, string message, object from) { _office->event_enter(ob, message, from); } /* event_enter() */ /** * Query the value of the register's contents. * @return the current value of the register's contents */ int query_register() { object cash = present(MONEY_ALIAS, _register); if (!cash) return 0; _money = cash->query_money_array() + ({}); return MONEY_HAND->query_total_value(_money, _place); } /* query_register() */ /** * @ignore yes * Saves the contents of the register whenever they change. * @param old the money array to save * @param word the object changing the register (player or "shop") */ private void save_me(string name) { int difference; object cash; mixed *old = _money + ({}); if (!_register) return; cash = present(MONEY_ALIAS, _register); if (!cash) _money = ({}); else _money = (mixed *)cash->query_money_array() + ({}); #ifdef DEBUG tell_creator(CREATOR, "Register contains: %O.\n", _money); #endif _office->save_register(_money); difference = MONEY_HAND->query_total_value(_money, _place) - MONEY_HAND->query_total_value(old, _place); if (!difference) return; _office->adjust_takings(difference); if (!name || name == "") return; if (difference < 0) _office->shop_log(PURCHASE, name, "removed "+ MONEY_HAND->money_value_string(-difference, _place)+ " from register", UNPAID); else _office->shop_log(SALE, name, "added "+ MONEY_HAND->money_value_string(difference, _place)+ " to register", UNPAID); } /* save_me() */ /** * @ignore yes * Save the register * @param no_player 0 if a player caused the register to save */ void save_register(int no_player) { remove_call_out(_call_save); _call_save = call_out((: save_me($((!no_player)? this_player()->query_name():"shop")) :), 1); } /* save_register() */ /** * Set the directions to other parts of the shop. * This function is used by the npc shopkeeper to navigate around the shop, * using the exits at the given directions. These directions should be the * standard "north", "southeast" etc. * @param office The direction to the office. * @param storeroom The direction to the store room. * @param shop The direction to the shop front. * @example set_directions( "west", "south", "east" ); * */ protected void set_directions(string office, string storeroom, string shop) { _office_dir = office; _store_dir = storeroom; _shop_dir = shop; } /* set_directions() */ /** * @ignore yes * Adding a bit of standard stuff to the set_long() * @param long_desc the long description */ protected void set_long(string long_desc) { long_desc += "Employees of the shop can \"log\" transactions or " "\"correction\"s here. The shop's cash register is under the " "counter and there is a calculator next to that.\n"; ::set_long(long_desc); } /* set_long() */ /** * Set the path of the main office. * Also sets up the and restores the register. * @example set_office( PATH + "tarnach's_office" ); * @param path The full path & filename to the office. */ protected void set_office(string path) { object cash; _office = path; _storeroom = _office->query_storeroom(); _mgr_office = _office->query_mgr_office(); _shop_front = _office->query_shop_front(); _place = _office->query_place(); if (_register) return; _register = clone_object("/obj/misc/cash_register"); _register->set_name("register"); _register->set_short("cash register"); _register->add_adjective("cash"); _register->set_long("The cash register is really just an iron drawer " "mounted underneath the counter. In a certain light, it almost " "seems tongue-shaped.\n"); _register->set_shop(this_object()); add_hidden_object(_register); _register->reset_get(); _money = _office->restore_register(); if (!_money || !sizeof(_money)) return; cash = clone_object(MONEY_OBJECT); cash->set_money_array(_money); cash->move(_register); } /* set_office() */