/****************************************************************************** * This file contains the personnel related functions *****************************************************************************/ /** * @ignore yes * Adds a new employee. * Also prevent the employee from receiving a bonus until they have * worked a full month by setting EMP_NOBONUS to 1. * @param player the employee to add */ private void add_employee(string player) { if (!_employees[player]) { _employees += ([player:EMP_MAP]); _employees[player][EMP_NOBONUS] = 1; set_emp_time(player); _got_bonus += ({player}); save_me(); save_emps(); } } /* add_employee() */ /** * @ignore yes * Demote a manager or supervisor. * @param demoter the person doing the demoting * @param demotee the person being demoted */ private void demote(string demoter, string demotee) { int points = _employees[demotee][EMP_POINTS] & CLOCKED_IN; if (_employees[demotee][EMP_POINTS] & MANAGER) points += (SUPER_POINTS * 32) + EMPLOYEE + SUPERVISOR; else points += EMPLOYEE; _employees[demotee][EMP_POINTS] = points; save_emps(); PLAYER_SHOP->auto_mail(demotee, _proprietor, "Demotion", "", "This is to advise you that you have today been demoted.\n" "This demotion will now stay on your employment record.\n"); employee_log(demotee, "Demoted by "+ demoter); shop_log(PERSONNEL, demoter, "demoted "+ cap_name(demotee), PAID); } /* demote() */ /** * @ignore yes * Managers' office. * Commend employees. Adds 5% of their promotion target. */ int do_commend(string emp) { string commender; if (!_employees[emp]) { tell_object(this_player(), cap_name(emp)+ " is not an active employee!\n"); return 1; } if (_employees[emp][EMP_POINTS] & MANAGER) { tell_object(this_player(), "You can't commend a manager.\n"); return 1; } if (_employees[emp][EMP_POINTS] & NPC) { tell_object(this_player(), "Don't be silly! " "You can't commend $C$"+ emp +".\n"); return 1; } commender = this_player()->query_cap_name(); AUTO_MAILER->auto_mail(emp, lower_case(commender), "Commendation", "", "This is to advise you that you have today received a " "commendation for outstanding service.\nThis will now stay on " "your employment record.\n"); employee_log(emp, "Received a commendation from "+ commender); shop_log(PERSONNEL, commender, "commended "+ cap_name(emp), PAID); _employees[emp][EMP_POINTS] += (_employees[emp][EMP_POINTS] & SUPERVISOR)? to_int(MANAGER_POINTS * 0.05 * 32) : to_int(SUPER_POINTS * 0.05 * 32); save_emps(); tell_object(this_player(), "You commend "+ cap_name(emp)+ ".\n"); return 1; } /* do_commend() */ /** * @ignore yes * Managers' office. * Demote supervisors or managers. */ int do_demote(string emp) { object tp = this_player(); emp = lower_case(emp); if (!_employees[emp]) { tell_object(tp, cap_name(emp)+ " is not an active employee!\n"); return 1; } if (_employees[emp][EMP_POINTS] & MANAGER && !tp->query_creator()) { tell_object(tp, "You don't have the authority to " "demote $C$"+ emp +".\n"); return 1; } if (!( _employees[emp][EMP_POINTS] & SUPERVISOR)) { tell_object(tp, "Don't be silly! You can't demote $C$"+ emp +".\n"); return 1; } demote(tp->query_cap_name(), emp); tell_object(tp, "You demote "+ cap_name(emp)+ ".\n"); return 1; } /* do_demote() */ /** * @ignore yes * Managers' office. * Fire an employee. */ int do_fire(mixed *args) { args[0] = lower_case(args[0]); if (!_employees[args[0]]) { tell_object(this_player(), cap_name(args[0])+ " doesn't work at the shop!\n"); return 1; } if ((member_array(args[0], _retired) != -1) || query_manager(args[0]) && !this_player()->query_creator()) { tell_object(this_player(), "You don't have the authority " "to fire $C$"+ args[0] +".\n"); return 1; } if (_employees[args[0]][EMP_POINTS] & NPC) { tell_object(this_player(), "Don't be silly! You can't fire $C$"+ args[0] +".\n"); return 1; } fire_them(this_player()->query_name(), args[0], args[1]); tell_object(this_player(), "You fire "+ cap_name(args[0])+ " for "+ args[1]+ ".\n" ); return 1; } /* do_fire() */ /** * @ignore yes * Managers' office. * Place an employee on leave. */ int do_leave(mixed *args) { object tp = this_player(); args[0] = lower_case(args[0]); if (!_employees[args[0]]) { tell_object(tp, cap_name(args[0])+ " is not an employee!\n"); return 1; } if (args[1] > MAX_LEAVE) { tell_object(tp, "You cannot place an employee on leave " "for more than "+ MAX_LEAVE+ " days at a time.\n"); return 1; } _times[args[0]] = time() + (args[1] * 86400); remove_call_out(_call_times); _call_times = call_out((: save_times() :), PERS_DELAY); add_succeeded_mess(cap_name(args[0])+ " is on leave until "+ ctime(time() + (args[1] * 86400))+ ".\n"); shop_log(PERSONNEL, tp->query_name(), "placed "+ cap_name(args[0])+ " on leave for " + args[1]+ " days", PAID); employee_log(args[0], "Placed on leave by "+ tp->query_cap_name()+ " for "+ args[1]+ " days."); tell_object(tp, "You place "+ cap_name(args[0])+ " on leave for " + args[1]+ " days.\n"); return 1; } /* do_leave() */ /** * @ignore yes * This employee has requested to be passed over (or not) for promotion. */ private int do_promote(string on) { object tp = this_player(); add_succeeded_mess(""); if (tp->query_creator()) { tell_object(tp, "Creators don't get promoted.\n"); return 1; } switch (on) { case "off" : _employees[tp->query_name()][EMP_NOPROMOTE] = TRUE; tell_object(tp, "You have now requested to be " "passed over for promotion.\n"); break; case "on" : if (tp->query_property("no score")) { tell_object(tp, "Sorry, you cannot be promoted.\n"); return 1; } _employees[tp->query_name()][EMP_NOPROMOTE] = FALSE; tell_object(tp, "You have now requested to be " "considered for promotion.\n"); break; } save_emps(); return 1; } /* do_promote() */ /** * @ignore yes * Employee wishes to terminate their employment with the shop. */ private int do_resign() { string word = this_player()->query_name(); add_succeeded_mess("$N $V.\n"); remove_employee(word); shop_log(PERSONNEL, word, "resigned", UNPAID); employee_log(word, "Resigned"); return 1; } /* do_resign() */ /** * @ignore yes * Managers' office. * Retire from management. */ int do_retire() { string manager = this_player()->query_name(); if (!(_employees[manager][EMP_POINTS] & MANAGER)) return 0; remove_employee(manager); _retired += ({manager}); shop_log(PERSONNEL, manager, "retired from management", UNPAID); employee_log(manager, "Retired from management"); save_me(); add_succeeded_mess("$N retire$s.\n"); return 1; } /* do_retire() */ /** * @ignore yes * Managers' office. * Suspend employee's bonus for x months. */ int do_suspend(mixed *args) { string suspender; object tp = this_player(); args[0] = lower_case(args[0]); if (!_employees[args[0]]) { tell_object(tp, cap_name(args[0])+ " is not an active employee!\n"); return 1; } if ((_employees[args[0]][EMP_POINTS] & MANAGER) && (!tp->query_creator())) { tell_object(tp, "You don't have the authority to " "suspend $C$"+ args[0] +"'s bonus.\n"); return 1; } if (_employees[args[0]][EMP_POINTS] & NPC) { tell_object(tp, "Don't be silly! " "You can't suspend $C$"+ args[0] +"'s bonus.\n"); return 1; } suspender = tp->query_cap_name(); _employees[args[0]][EMP_NOBONUS] = args[1]; save_emps(); AUTO_MAILER->auto_mail(args[0], _proprietor, "Suspended bonus", "", sprintf( "This is to advise you that you have had your bonus " "entitlement suspended for %d month%s.\nThis suspension will " "now stay on your employment record.\n", args[1], (args[1] == 1)?"":"s")); employee_log(args[0], sprintf("Bonus suspended for %d month%s by %s", args[1], (args[1] == 1)?"":"s", suspender)); shop_log(PERSONNEL, suspender, sprintf("suspended %s's bonus for %d month%s", args[0], args[1], (args[1] == 1)?"":"s"), PAID); tell_object(tp, "You suspend "+ cap_name(args[0])+ "'s bonus for "+ args[1]+ " months.\n"); return 1; } /* do_suspend() */ /** * @ignore yes * Managers' office. * Warn employees. Removes 5% of their promotion target. */ int do_warn(mixed *args) { string warner; object tp = this_player(); int points; args[0] = lower_case(args[0]); if (!_employees[args[0]]) { tell_object(tp, cap_name(args[0])+ " is not an active employee!\n"); return 1; } if (_employees[args[0]][EMP_POINTS] & MANAGER && !tp->query_creator() ) { tell_object( tp, "You don't have the authority to " "warn $C$"+ args[0] +".\n" ); return 1; } if (_employees[args[0]][EMP_POINTS] & NPC) { tell_object(tp, "Don't be silly! You can't warn $C$"+ args[0] +".\n"); return 1; } warner = tp->query_cap_name(); AUTO_MAILER->auto_mail(args[0], _proprietor, "Official warning", "", "This is to advise you that you have today received a formal " "warning for " + args[1] + ".\nThis warning will now stay on " "your employment record.\n"); employee_log(args[0], "Received a warning from "+ warner+ " for "+ args[1]); shop_log(PERSONNEL, warner, "warned "+ cap_name( args[0] ) + " for "+ args[1], PAID); points = _employees[args[0]][EMP_POINTS] & CLOCKED_IN; if (_employees[args[0]][EMP_POINTS] & SUPERVISOR) _employees[args[0]][EMP_POINTS] -= to_int(MANAGER_POINTS * 0.05 * 32); else { _employees[args[0]][EMP_POINTS] -= to_int(SUPER_POINTS * 0.05 * 32) + EMPLOYEE; if (_employees[args[0]][EMP_POINTS] < 1) _employees[args[0]][EMP_POINTS] = EMPLOYEE + points; } save_emps(); tell_object(tp, "You warn "+ cap_name(args[0])+ " for "+ args[1]+ ".\n"); return 1; } /* do_warn() */ /** * @ignore yes * Used when employees are fired by managers, or automatically. * @param word the person doing the firing * @param them the person being fired * @param reason the reason for being fired */ private void fire_them(string word, string them, string reason) { if (!_employees[them]) return; BANK_HANDLER->adjust_account(them, BANKS[_employees[them][EMP_BANK]][1], _employees[them][EMP_PAY]); shop_log(ACCOUNTS, _proprietor, "paid "+ MONEY_HAND->money_value_string(_employees[them][EMP_PAY], _place)+ " to "+ cap_name(them), UNPAID); shop_log(PERSONNEL, word, "fired "+ cap_name(them) + " for "+ reason, PAID); PLAYER_SHOP->auto_mail(them, word, _shop_name, "", "Unfortunately, I have to inform you that you have today " "been fired for " + reason + ". You have been paid the sum of "+ MONEY_HAND->money_value_string( _employees[them][EMP_PAY], _place )+ " for the work you have carried out to this date.\nIf you feel you " "have been unfairly dismissed, please refer to a manager.\n"); employee_log(them, "Fired by "+ cap_name(word)+ " for "+ reason); remove_employee(them); } /* fire_them() */ /** * @ignore yes * Used when applicant has sufficient supporting votes to be accepted. * @param word the person to hire */ private void hire(string word) { int gender; remove_applicant(word); /* Do not hire if not a user, already an employee, or banned */ if (!test_player(word) || _employees[word] || query_baddie(word)) return; add_employee(word); employee_log(word, "Hired"); shop_log(PERSONNEL, _proprietor, "hired "+ cap_name(word), UNPAID); PLAYER_SHOP->auto_mail(word, _proprietor, _shop_name, "", "Congratulations! You've been hired to work at "+ _shop_name+ ". You'll find that you can now move through the counter " "to the back areas of the shop. The first things you should " "do are \"claim\" a new badge and staff handbook.\n"); gender = PLAYER_HANDLER->test_gender(word); add_board_message("New employee", sprintf("%s has today been employed to " "work for the shop. Please make %s feel welcome, and assist %s while " "%s gets started in %s new position.\n", cap_name(word), ({"it", "him", "her"})[gender] ,({"it", "him", "her"})[gender], ({"it", "he", "she"})[gender], ({"its", "his", "her"})[gender])); /* Update the other accepted applicants */ remove_call_out(_call_mail_hirees); _call_mail_hirees = call_out((: mail_hirees() :), 5); } /* hire() */ /** * @ignore yes * Used by the employee list to show managers & creators the last * time an employee was active. Employees will be highlighted yellow * if they are currently on an inactivity warning, and red if they are * within 7 days of being fired/demoted * @param emp the employee to query */ private string query_worked(string emp) { string blurb; /* Clocked in */ if (_employees[emp][EMP_POINTS] & CLOCKED_IN) return " is currently clocked in"; /* NPC */ if (_employees[emp][EMP_POINTS] & NPC) return " has gone home for tea"; /* On leave */ if (_times[emp] > time()) return " - %^CYAN%^on leave until "+ ctime(_times[emp])+ "%^RESET%^"; blurb = " - last action "; if (_employees[emp][EMP_POINTS] & MANAGER) { if ((time() - _times[emp]) > ((60*60*24*MGR_DEMOTE)-7)) blurb += "%^RED%^"; else if ((time() - _times[emp]) > (60*60*24*MGR_WARN)) blurb += "%^RED%^"; } else if (_employees[emp][EMP_POINTS] & SUPERVISOR) { if (( time() - _times[emp]) > ((60*60*24*SPR_DEMOTE)-7)) blurb += "%^RED%^"; else if ((time() - _times[emp]) > (60*60*24*SPR_WARN)) blurb += "%^YELLOW%^"; } else if (( time() - _times[emp]) > ((60*60*24*EMP_FIRE)-7)) blurb += "%^RED%^"; else if ((time() - _times[emp]) > (60*60*24*EMP_WARN)) blurb += "%^YELLOW%^"; return blurb + ctime(_times[emp])+ "%^RESET%^"; } /* query_worked() */ /** * @ignore yes * Sets the last action time of an employee. * This time is the last time an employee did something worth * recording and is used to determine if they are inactive. * @param employee The employee. */ private void set_emp_time(string employee) { if (!_employees[employee]) return; if (_employees[employee][EMP_INACTIVE]) { _employees[employee][EMP_INACTIVE] = 0; // Reset inactivity flag save_emps(); } if (!sizeof(_times)) _times = ([employee:0]); else if (!_times[employee]) _times += ([employee:0]); _times[employee] = time(); remove_call_out(_call_times); _call_times = call_out((: save_times() :), PERS_DELAY); } /* set_emp_time() */ /** * @ignore yes * View an employee's history or an applicant's application. * This method displays a formatted display of the employee's history * with a particular shop, and is viewable by managers of that shop. * If passed the name of an applicant, it will view the relevant application. * @param person The employee or applicant. */ void view_record(string person, string pattern) { if (pattern == VIEW_EMP) { string text = sprintf("Employment history of %s:\n\n", cap_name(person)); load_history(); if (!sizeof(_history) || !_history[person]) { tell_object(this_player(), "There is no history for that person.\n"); return; } for(int i = 0; i < sizeof(_history[person][0]); i++) text += sprintf("%s: %s\n", ctime(_history[person][0][i]), _history[person][1][i]); tell_object(this_player(), sprintf("$P$%s's history$P$%s", cap_name(person), text)); clear_history(); } else { if (!query_applicant(person)) { tell_object(this_player(), "That person has no application form " "on file.\n"); return; } load_applicants(); tell_object(this_player(), sprintf("$P$%s's history$P$Application of %s:\n\n%s", cap_name(person), cap_name(person), _applicants[person][APP_MESSAGE])); clear_applicants(); } } /* view_record() */