/****************************************************************************** * This file contains the code to deal with the maintenance reviews *****************************************************************************/ /** * @ignore yes * Called once a month to conduct the shop's monthly review. * This method is the monthly maintenance function for the shop. This review * involves paying employees direct into their nominated bank account, and * awarding bonuses based on the current value of the bonus fund. If there is * not enough money in the profit account to pay the correct amount, the * employees are paid on a pro-rata basis. */ private void monthly_review() { int amount = calc_pay(), bonus_divisor = 0, cabinet_cost = (_num_cabinets - MIN_CABINETS) * CABINET_COST, pay; float pay_multiplier = 1.0; string *emps = m_indices(_employees); log_file("/log/PLAYER_SHOP", "%s: %s entered monthly review (review.c)\n", ctime(time()), _very_short); if (cabinet_cost) { adjust_profit(_proprietor, -cabinet_cost); shop_log(ACCOUNTS, _proprietor, "paid "+ MONEY_HAND->money_value_string(cabinet_cost, _place) + " for the rent of " + (_num_cabinets - MIN_CABINETS) + " cabinets", UNPAID); } if (_accounts["profit"] < 0) adjust_bonus("Shop",_accounts["profit"]); if (amount > _accounts["profit"]) pay_multiplier = _accounts["profit"] / amount; foreach (string word in emps) { if (!_employees[word][EMP_PAY]) continue; pay = to_int(_employees[word][EMP_PAY] * pay_multiplier); if (!(_employees[word][EMP_POINTS] & NPC)) { BANK_HANDLER->adjust_account(word, BANKS[_employees[word][EMP_BANK]][1], pay ); PLAYER_SHOP->auto_mail(word, _proprietor, "Pay advice for "+ _last_month, "", sprintf("For your work during %s, you have been " "paid a total of %s. Keep up the good work.\n--\n%s " "(proprietor)\n", _last_month, MONEY_HAND->money_value_string(pay, _place ), _proprietor)); } else _employees[word][EMP_POINTS] = EMPLOYEE + NPC; shop_log(ACCOUNTS, _proprietor, "paid "+ MONEY_HAND-> money_value_string(pay, _place)+ " to "+ cap_name(word), UNPAID); _employees[word][EMP_PAY] = 0; _accounts["profit"] -= pay; } _bonus += _accounts["bonus"]; if (_bonus < 0) { _accounts["bonus"] = _bonus; _bonus = 0; } else _accounts["bonus"] = 0; foreach (string word in m_indices(_employees)) { if (_employees[word][EMP_NOBONUS]) continue; if (!test_prop(word, _very_short+ " handbook")) continue; if (_employees[word][EMP_POINTS] & MANAGER) { bonus_divisor += 4; } else if (_employees[word][EMP_POINTS] & SUPERVISOR || _eom == word) { bonus_divisor += 3; } else { bonus_divisor += 2; } } if (!bonus_divisor) _bonus_val = _bonus; else _bonus_val = (_bonus * 2) / bonus_divisor; _got_bonus = ({}); _eom = sort_array(get_employees(), (: _employees[$2][EMP_EOM] - _employees[$1][EMP_EOM] :))[0]; foreach (string word in m_indices(_employees)) { if (_employees[word][EMP_NOBONUS]) { _employees[word][EMP_NOBONUS]--; _got_bonus += ({word}); } _employees[word][EMP_EOM] = 0; } employee_log(_eom, _last_month+ "'s Employee Of The Month"); add_board_message("Bonuses for "+ _last_month, sprintf("Based on the bonus fund of %s for %s, the following " "bonuses have been awarded:\n\n Managers - %s\n Supervisors" " - %s\n Employees - %s\n\n%s's Employee Of The Month was %s. " "Well done to you.\n", MONEY_HAND->money_value_string(_bonus, _place), _last_month, MONEY_HAND->money_value_string(_bonus_val * 2, _place), MONEY_HAND->money_value_string(to_int(_bonus_val * 1.5), _place), MONEY_HAND->money_value_string(_bonus_val, _place), _last_month, cap_name(_eom))); if (_bonus) { shop_log( ACCOUNTS, _proprietor, "paid out "+ MONEY_HAND->money_value_string(_bonus, _place)+ " in bonuses for "+ _last_month, UNPAID ); } if (_eom == _shopkeeper->query_name()) { _bonus -= to_int(_bonus_val * 1.5); shop_log(GENERAL, _eom, "claimed "+ MONEY_HAND->money_value_string(to_int(_bonus_val * 1.5), _place), UNPAID); } else { _bonus -= _bonus_val; shop_log(GENERAL, _shopkeeper->query_name(), "claimed "+ MONEY_HAND->money_value_string(_bonus_val, _place), UNPAID); } if (_bonus < 0) _bonus = 0; _last_month = _review_month; _call_review = 0; save_me(); save_emps(); } /* monthly_review() */ /** * @ignore yes * Called once a day to conduct the shop's daily review. * This method is the daily maintenance function for the shop. It checks that * employees are still valid players, and not creators. It conducts automatic * promotions, and handles demotions for inactive employees. It also updates * the lists of declined applicants and banned people and removes that status * if applicable. Finally, it calls the check_hire_list function to see if * we can hire any new employees. */ private void review_employees() { int prom = FALSE, prom_number, managers, time = time(); string *promos = ({}), promopost, *emps = _retired + m_indices(_employees); log_file("/log/PLAYER_SHOP", "%s: %s entered review_employees (review.c)\n", ctime(time()), _very_short); /* Fire non-users, creators and demote creator alts */ foreach (string word in emps) { if (!test_player(word)) { /* Make sure we are not firing the npc shopkeeper */ if (_employees[word][EMP_POINTS] & NPC) continue; fire_them(_proprietor, word, "not existing"); } else if (test_cre(word)) fire_them(_proprietor, word, "being a creator"); else if (test_prop(word,"no score") && _employees[word][EMP_POINTS] & SUPERVISOR ) { _employees[word][EMP_POINTS] = _employees[word][EMP_POINTS] & CLOCKED_IN + EMPLOYEE; save_emps(); PLAYER_SHOP->auto_mail(word, _proprietor, "Demotion", "", "This is to advise you that, due to you having a creator alt, " "you have today been demoted.\n"); employee_log(word, "Demoted by "+ _proprietor); shop_log(PERSONNEL, _proprietor, "demoted "+ cap_name(word), UNPAID); } if (!test_prop(word, _very_short+ " handbook")) { _employees[word][EMP_PAY] = 0; _employees[word][EMP_POINTS] = _employees[word][EMP_POINTS] & CLOCKED_IN + EMPLOYEE; } } /* Check for inactive managers */ foreach (string word in get_managers()) if ((time - _times[word]) > (60*60*24*MGR_DEMOTE) && _employees[word][EMP_INACTIVE] && last_login(word) - _times[word] > (60*60*24*2)) demote( _proprietor, word ); else if (time - _times[word] > (60*60*24*MGR_WARN) && !_employees[word][EMP_INACTIVE] && last_login(word) - _times[word] > (60*60*24*2)) { PLAYER_SHOP->auto_mail(word, _proprietor, "Poor attendance", "", "It has come to my attention that you have now been " "inactive for over " + MGR_WARN+ " days. As you are a manager, " "you are required to meet certain levels of attendance. " "You are now in serious danger of being demoted without " "further warning.\n---\n" + _proprietor+ " (proprietor)\n"); _employees[word][EMP_INACTIVE] = TRUE; employee_log(word, "Warned about inactivity"); shop_log(PERSONNEL, _proprietor, "warned "+ cap_name(word) + " about inactivity", UNPAID); } /* Check supervisors for inactivity or promotion. Sorted by points so * people promoted in order. */ foreach(string word in sort_array(get_supervisors(), (: _employees[$1][EMP_POINTS] - _employees[$2][EMP_POINTS] :))) if (time - _times[word] > (60*60*24*SPR_DEMOTE) && _employees[word][EMP_INACTIVE] && last_login(word) - _times[word] > (60*60*24*2)) demote( _proprietor, word ); else if (time - _times[word] > (60*60*24*SPR_WARN) && !_employees[word][EMP_INACTIVE] && last_login(word) - _times[word] > (60*60*24*2)) { PLAYER_SHOP->auto_mail(word, _proprietor, "Poor attendance", "", "It has come to my attention that you have now been " "inactive for over "+ SPR_WARN+ " days. As you are a supervisor, " "you are required to meet certain levels of attendance. " "You are now in serious danger of being demoted without " "further warning.\n---\n" + _proprietor+ " (proprietor)\n"); _employees[word][EMP_INACTIVE] = TRUE; employee_log(word, "Warned about inactivity"); shop_log(PERSONNEL, _proprietor, "warned "+ cap_name(word) + " about inactivity", UNPAID); } else { /* See if any managerial vacancies. If so, and this person has * sufficient points & is not being ignored for promotion, * promote them. */ prom_number = (_max_emp * PERCENT_M) / 100; if ((_employees[word][EMP_POINTS] > 32 * MANAGER_POINTS) && sizeof(get_managers()) < prom_number && !_employees[word][EMP_NOPROMOTE]) { set_employee(word, MANAGER); shop_log(PERSONNEL, _proprietor, "promoted "+ cap_name(word)+ " to manager", UNPAID); employee_log(word, "Promoted to manager"); PLAYER_SHOP->auto_mail(word, _proprietor, "Promotion!", "", "Congratulations! You've been promoted to manager " "of "+ _shop_name+ ". You'll find that you can now enter " "the managers' office. Please remember to use the \"memo\" " "facility from there to discuss any major admin points with " "other managers. This includes hiring, firing, and so on.\n"); promos += ({word}); prom = TRUE; } } /* Check employees for inactivity or promotion. Sorted by points so * people promoted in order. */ foreach(string word in sort_array(get_employees(), (: _employees[$1][EMP_POINTS] - _employees[$2][EMP_POINTS] :))) { if (_employees[word][EMP_POINTS] & NPC) continue; if (time - _times[word] > (60*60*24*EMP_FIRE) && _employees[word][EMP_INACTIVE] && last_login(word) - _times[word] > (60*60*24*2)) { fire_them(_proprietor, word, "serious inactivity"); continue; } if (time - _times[word] > (60*60*24*EMP_WARN)) { if (!_employees[word][EMP_INACTIVE] && last_login(word) - _times[word] > (60*60*24*2)) { PLAYER_SHOP->auto_mail(word, _proprietor, "Inactivity", "", "It has come to my attention that you have now been " "inactive for over "+ EMP_WARN+ " days. Unless this " "situation is resolved, the management may have no option " "but to terminate your employment.\n---\n"+ _proprietor+ " (proprietor)\n"); _employees[word][EMP_INACTIVE] = TRUE; shop_log(PERSONNEL, _proprietor, "warned "+ cap_name(word)+ " about inactivity", UNPAID); employee_log(word, "Warned about inactivity"); } } else { /* See if any supervisory vacancies. If so, and this person has * sufficient points & is not being ignored for promotion, * promote them. */ prom_number = (_max_emp * PERCENT_S) / 100; if ((_employees[word][EMP_POINTS] > 32 * SUPER_POINTS) && sizeof( get_supervisors() ) < prom_number && !_employees[word][EMP_NOPROMOTE]) { if(_employees[word][EMP_POINTS] & CLOCKED_IN) _employees[word][EMP_POINTS] = (SUPER_POINTS * 32) + EMPLOYEE+ SUPERVISOR + CLOCKED_IN; else _employees[word][EMP_POINTS] = (SUPER_POINTS * 32) + EMPLOYEE+ SUPERVISOR; shop_log(PERSONNEL, _proprietor, "promoted "+ cap_name(word)+ " to supervisor", UNPAID); employee_log(word, "Promoted to supervisor"); PLAYER_SHOP->auto_mail(word, _proprietor, "Promotion!", "", "Congratulations! You've been promoted to supervisor " "of "+ _shop_name+ ". You will now be able to use your " "newly acquired supervisor commands.\n"); promos += ({word}); prom = TRUE; } } } /* Post about promotions */ if (prom) { promopost = "The following employees have been promoted:\n\n"; foreach (string word in promos) promopost += sprintf(" %s has been promoted to %s\n", cap_name(word), (_employees[word][EMP_POINTS] & MANAGER)? "manager":"supervisor"); promopost += "\nCongratulations!\n"; add_board_message("Promotions", promopost); } /* Check the list of banned people */ foreach (string word in m_indices(_baddies)) if (time - _baddies[word][BAD_TIME] > (60*60*24*BAN_LENGTH)) remove_baddie( word ); /* Check the list of declined applicants */ foreach (string word in m_indices(_declined)) if (time - _declined[word] > (60*60*24*DECLINE_LENGTH)) remove_declined(word); /* See if anyone can be hired */ remove_call_out(_call_hire_list); _call_hire_list = call_out((: check_hire_list() :), 5); save_emps(); /* Update policies */ managers = sizeof(get_managers()) + sizeof(get_retired()); load_new_policies(); if (sizeof(_new_policies)) { foreach (string word in m_indices(_new_policies)) { if (sizeof(_new_policies[word][POLICY_FOR]) > managers / 2) { add_policy(word); } else if (time - _new_policies[word][POLICY_TIME] > VOTE_TIMEOUT) { if (sizeof(_new_policies[word][POLICY_FOR]) >= sizeof(_new_policies[word][POLICY_AGAINST])) { add_policy(word); } else remove_policy(word); } } } clear_new_policies(); /* Update the player history data */ load_history(); foreach (string word in m_indices(_history)) { if (!test_player(word) || test_cre(word) || !_times[word] || _times[word] < (time - HIST_TIMEOUT)) { map_delete(_times, word); map_delete(_history, word); } } save_hist(); save_times(); } /* review_employees() */