/****************************************************************************** * This file contains misc admin functions *****************************************************************************/ /** * @ignore yes * Writes a message to the shop's board if it exists. If not, will * send a mail to each employee. This message is "written" by the shop's * proprietor. * @param subject Take a guess ;-) * @param post See subject... */ private void add_board_message(string subject, string post) { string *employees; if (_board) { #ifdef DEBUG tell_creator(CREATOR, "Posting message %s to board %s.\n", subject, _channel); #endif BOARD_HAND->add_message(_channel, _proprietor, subject, post + "--\n"+ _proprietor+ " (proprietor)"); } else { employees = _retired; foreach(string employee in m_indices(_employees)) if (!(_employees[employee][EMP_POINTS] & NPC)) employees += ({ employee }); if (!sizeof(employees)) { #ifdef DEBUG tell_creator(CREATOR, "No employees to send mail to.\n"); #endif return; } employees += ({CREATOR}); #ifdef DEBUG tell_creator(CREATOR, "Sending mail %s to all employees.\n", subject); #endif AUTO_MAILER->auto_mail(implode(employees, ","), _proprietor, subject+ " ("+ _very_short+ ")", "", post); } } /* add_board_message() */ /** * @ignore yes * Adjust the value of the bonus account. * @param emp the employee adjusting the account * @param amount the amount to adjust the account by */ private void adjust_bonus(string emp, int amount) { string sign = ""; _accounts["bonus"] += amount; if (amount < 0) { sign = "-"; amount = -amount; } shop_log( ACCOUNTS, emp, sprintf( "adjusted the bonus account by %s%s", sign, MONEY_HAND->money_value_string( amount, _place ) ), UNPAID ); save_me(); } /* adjust_bonus() */ /** * @ignore yes * Adjust the value of the profit account. * @param emp the employee adjusting the account * @param amount the amount to adjust the account by */ private void adjust_profit(string emp, int amount) { string sign = ""; _accounts["profit"] += amount; if (amount < 0) { sign = "-"; amount = -amount; } shop_log(ACCOUNTS, emp, sprintf("adjusted the profit account by %s%s", sign, MONEY_HAND->money_value_string(amount, _place)), UNPAID); save_me(); } /* adjust_profit() */ /** * @ignore yes * Keep track of net change in register. * @param amt the amount to adjust by */ void adjust_takings(int amt) { if (previous_object() && previous_object() != find_object(_counter)) { LOG_ERROR("office.c", "adjust_bought("+amt+")"); return; } _net_takings += amt; save_me(); } /* adjust_takings() */ /** * @ignore yes * Calculate the months' projected bonuses. * These values are based upon the current staff levels, as well as * the amount of money in the bonus account. The result is written * directly to this_player(). */ void calc_bonus() { int bonus_val, bonus_divisor = 0; foreach (string str in m_indices(_employees)) { if (_employees[str][EMP_NOBONUS]) continue; if (_employees[str][EMP_POINTS] & MANAGER) { bonus_divisor += 4; } else if (_employees[str][EMP_POINTS] & SUPERVISOR || _eom == str) { bonus_divisor += 3; } else { bonus_divisor += 2; } } if (!bonus_divisor) bonus_val = _accounts["bonus"]; else bonus_val = ( _accounts["bonus"] * 2 ) / bonus_divisor; tell_object(this_player(), "Based on the bonus fund of "+ MONEY_HAND->money_value_string(_accounts["bonus"], _place)+ ", the following bonuses are anticipated:\n" "\n Managers - "+ MONEY_HAND->money_value_string(bonus_val * 2, _place)+ "\n Supervisors - "+ MONEY_HAND->money_value_string(to_int(bonus_val * 1.5), _place)+ "\n Employees - "+ MONEY_HAND->money_value_string(bonus_val, _place)+ "\n"); } /* calc_bonus() */ /** * @ignore yes * Calculate total employee wage packet for this month. * This will calculate the wage bill for the current month, correct at the * time of calculation. It is given in base units, and will need converting * to local currency if it is to be displayed. * @return the current value of the months' wages. */ int calc_pay() { int amount = 0; foreach(string word in m_indices(_employees)) amount += _employees[word][EMP_PAY]; return amount; } /* calc_pay() */ /** @ignore yes */ private string cap_name(string name) { if (!name) return 0; if (test_player(name)) return PLAYER_HANDLER->query_cap_name(name); else return capitalize(name); } /** * @ignore yes * Used to check access to the managers' office. * Called when someone attempts to use the door modified by add_manager_exit() * @see add_manager_exit() * @param action open/close * @return 1 to allow access */ int check_manager( string action ) { object tp = this_player(); string tp_name = tp->query_name(); if (tp->query_creator() || (_employees[tp_name][EMP_POINTS] & MANAGER) || (member_array(tp_name, _retired) != -1)) return 1; return notify_fail( "You are not a manager here!\n" ); } /* check_manager() */ /** * @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 place to get directions to * @return the exit from this room leading to place */ string directions_to( string place ) { if (place == _counter) return copy(_counter_dir); if (place == _storeroom) return copy(_store_dir); if (place == _shop_front) return copy(_shop_dir); return "here"; } /* directions_to() */ /** * @ignore yes * Managers' office. * Set maximum employees & base pay rate. */ int do_set(mixed *args, string pattern) { int value, best; object money; switch(pattern) { case SET_EMPS : if (args[0] < MIN_EMP || args[0] > MAX_EMP) { tell_object(this_player(), "Must be between "+ MIN_EMP+ " and "+ MAX_EMP+ ".\n"); return 1; } shop_log(PERSONNEL, this_player()->query_name(), "set maximum employees to "+ args[0], PAID); _max_emp = args[0]; break; case SET_PAY : money = clone_object( MONEY_OBJECT ); money->set_money_array(MONEY_HAND->query_values_in(_place)); if ((best = money->find_best_fit(args[1])) == -1) { tell_object(this_player(), "That currency is not used by the shop.\n"); return 1; } value = args[0] * (money->query_money_array())[best + 1]; money->dest_me(); if (value < 1) { tell_object(this_player(), "You must pay your employees something.\n"); return 1; } shop_log(PERSONNEL, this_player()->query_name(), "set pay to "+ MONEY_HAND->money_value_string(value, _place), PAID); _pay_val = value; add_board_message("Pay", sprintf("The base pay rate has today " "been set to:\n\n Managers: %s\n Supervisors: %s\n " "Employees: %s\n", MONEY_HAND->money_value_string(value * 2, _place), MONEY_HAND->money_value_string(to_int(value * 1.5), _place), MONEY_HAND->money_value_string(value, _place))); break; } tell_object(this_player(), "Ok.\n"); save_me(); return 1; } /* do_set() */ /** * @ignore yes * Managers' office. * Transfer money between accounts. */ int do_transfer(mixed *args) { int value, best; object money; string tp; if (args[2] == args[3] || !args[0]) { tell_object(this_player(), "The point being?\n"); return 1; } tp = this_player()->query_name(); money = clone_object(MONEY_OBJECT); money->set_money_array(MONEY_HAND->query_values_in(_place)); if ((best = money->find_best_fit(args[1])) == -1) { tell_object(this_player(), "That currency is not used by " "the shop.\n"); return 1; } value = args[0] * (money->query_money_array())[best + 1]; money->dest_me(); switch(args[2]) { case "register" : if (_counter->query_register() < value) { tell_object(this_player(), "There isn't that much available.\n"); return 1; } _counter->adjust_register(tp, value); if (args[3] == "profit") adjust_profit(tp, value); else adjust_bonus( tp, value ); break; case "bonus" : if (_accounts["bonus"] < value) { tell_object(this_player(), "There isn't that much available.\n"); return 1; } adjust_bonus(tp, -value); if (args[3] == "profit") adjust_profit(tp, value); else { money = MONEY_HAND->make_new_amount(value, _place); _counter->add_money_ob(money); shop_log(ACCOUNTS, tp, "adjusted the register by "+ MONEY_HAND->money_value_string(value, _place), UNPAID); } break; case "profit" : if (_accounts["profit"] < value) { tell_object(this_player(), "There isn't that much available.\n"); return 1; } adjust_profit(tp, -value); if (args[3] == "bonus") adjust_bonus( tp, value ); else { money = MONEY_HAND->make_new_amount(value, _place); _counter->add_money_ob(money); shop_log( ACCOUNTS, tp, "adjusted the register by "+ MONEY_HAND->money_value_string(value, _place), UNPAID); } break; } shop_log (ACCOUNTS, tp, "transferred "+ args[0]+ " "+ args[1]+ " from "+ args[2]+ " to "+ args[3], PAID); tell_object(this_player(), "Ok.\n"); return 1; } /* do_transfer() */ /** @ignore yes */ private void load_applicants() { if (remove_call_out(_call_apps) != -1 || remove_call_out(_call_apps_clear) != -1) return; if (!_applicants) if (file_size(_savedir+ "applications") > 0) _applicants = restore_variable(unguarded((: read_file, _savedir+ "applications" :))); else _applicants = ([]); } /* load_applications() */ /** @ignore yes */ private void load_history() { if (remove_call_out(_call_hist) != -1 || remove_call_out(_call_hist_clear) != -1) return; if (!_history) if (file_size(_savedir+ "history") > 0) _history = restore_variable(unguarded((: read_file, _savedir+ "history" :))); else _history = ([]); } /* load_history() */ /** @ignore yes */ private void load_new_policies() { if (remove_call_out(_call_newpols) != -1 || remove_call_out(_call_newpols_clear) != -1) return; if (!_new_policies) if ( file_size(_savedir+ "new_policies") > 0 ) _new_policies = restore_variable(unguarded((: read_file, _savedir+ "new_policies" :))); else _new_policies = ([]); } /* load_new_policies() */ /** @ignore yes */ private void load_policies() { if (remove_call_out(_call_pols) != -1 || remove_call_out(_call_pols_clear) != -1) return; if (!_policies) if ( file_size( _savedir+ "policies" ) > 0 ) _policies = restore_variable( unguarded( (: read_file, _savedir+ "policies" :) ) ); else _policies = ([]); } /* load_policies() */ /** @ignore yes */ string * query_eom() { return ({_last_month,_eom,}); } /** * @ignore yes * Remove this person from the employees mapping. * Used when an employee is fired, resigns, or retires. * @param employee the name of the employee to remove */ private void remove_employee(string employee) { employee = lower_case(employee); if (_employees[employee]) { map_delete(_employees, employee); save_emps(); } remove_applicant(employee); remove_retired(employee); /* Check to see if anyone should be hired */ remove_call_out(_call_hire_list); _call_hire_list = call_out((: check_hire_list() :), 5); } /* remove_employee() */ /** * @ignore yes * Remove this person from the retired managers array. * Used when a retired manager resigns. * @param retired the name of the employee to remove */ private void remove_retired(string retired) { retired = lower_case(retired); if (member_array(retired, _retired) == -1) return; _retired -= ({retired}); save_me(); } /* remove_retired() */ /** * @ignore yes * Employee bits are reset on clocking out. * @param word the name of the employee to reset * @param bit the bit(s) to reset * @see /include/player_shop.h */ private void reset_employee(string word, int bit) { if (!_employees[word]) return; if ((bit < EMPLOYEE) || (bit > CLOCKED_IN)) { #ifdef DEBUG tell_creator(CREATOR, "Trying to reset an employee bit < %d || > %d\n", EMPLOYEE, CLOCKED_IN ); #endif return; } _employees[word][EMP_POINTS] -= _employees[word][EMP_POINTS] & bit; if (bit != CLOCKED_IN) save_emps(); } /* reset_employee() */ /** * @ignore yes * Loading the contents of the shop's register. * @return a mixed monetary array to place in the register */ mixed *restore_register() { return copy(_register + ({})); } /** * @ignore yes * Employee bits are set upon promotion, or when clocking in. * @param word the name of the employee to set * @param bit the bit(s) to set * @see /include/player_shop.h */ // private void set_employee(string word, int bit) void set_employee(string word, int bit) { if (!_employees[word]) return; /* if ((bit < EMPLOYEE) || (bit > CLOCKED_IN)) { #ifdef DEBUG tell_creator(CREATOR, "Trying to set an employee bit < %d || > %d\n", EMPLOYEE, CLOCKED_IN); #endif return; } */ _employees[word][EMP_POINTS] |= bit; if (bit != CLOCKED_IN) save_emps(); } /* set_employee() */ /** * @ignore yes * Loads the npc shopkeeper and calls him/her/it to work. Will only reload * the npc once every NPC_DELAY, unless clock_out is non-zero in which case the * npc will be loaded regardless - this parameter indicates that the npc is * being recalled due to an employee clocking out. */ void summon_shopkeeper() { object shopkeeper = find_object(_shopkeeper); /* Already loaded */ if (shopkeeper && environment(shopkeeper)) return; /* Don't appear if any employees in */ if (num_employees_in()) return; _shopkeeper->start_shift(); } /* summon_shopkeeper() */