00001
00002
00003
00004
00005
00006
00007 #include <OMATH.H>
00008
00009
00010 #include <OSYS.H>
00011 #include <OINFO.h>
00012 #include <OPEERSCH.h>
00013 #include <OSCHLRES.h>
00014 #include <OPSCHOOL.h>
00015 #include <OFinance.h>
00016 #include <ODEVELOP.h>
00017 #include <OCHANCE.H>
00018 #include <Odeptres.h>
00019 #include <Odept.h>
00020 #include "OFacilit.h"
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 enum {
00034 COEF_COUNT = MAX_STUDENT_LEVEL+2,
00035 };
00036
00037 static const float parking_demand_coef[ENVIRONMENT_COUNT][COEF_COUNT] = {
00038 {0.70f, 0.40f, 0.00f, 0.45f, 0.65f, 0.70f, 0.50f},
00039 {1.00f, 0.65f, 0.10f, 0.60f, 0.80f, 0.90f, 0.80f},
00040 {1.00f, 0.90f, 0.25f, 1.00f, 1.00f, 1.00f, 1.00f},
00041 };
00042
00043
00044
00045
00046
00048
00049
00050
00051 PeerSchool *playerSchoolEx = school_res.player_peer_school;
00052
00053 finance.total_operating_expense.total = playerSchoolEx->total_operating_expenditure;
00054 finance.expense_array[AC_ACADEMIC_DEPARTMENTS].total = playerSchoolEx->dept_expense_faculty_salaries + playerSchoolEx->dept_expense_staff_salaries + playerSchoolEx->dept_expense_other;
00055 finance.expense_array[AC_SPONSORED_RESEARCH_EXPENSE].total = playerSchoolEx->sponsored_research / (1+playerSchoolEx->overhead_rate_on_sponsored_research/100.0);
00056
00057 begin_space_inventory();
00058
00059 department_res.general_dept_info.actual_sf = 0;
00060
00061
00062
00063 DepartmentInfo *deptInfo;
00064
00065
00066 int deptCount = department_array.department_count;
00067
00068 total_normal_onm = 0;
00069
00070
00071
00072 for( int i=0 ; i<=deptCount; i++ ) {
00073 if (i) {
00074
00075 deptInfo = (department_res.info_array+department_array[i]->department_id - 1);
00076 }
00077 else {
00078
00079
00080 deptInfo = &department_res.general_dept_info;
00081 }
00082
00083 float normalOnm = (deptInfo->actual_sf * deptInfo->normal_onm_cost / 1000.0f);
00084 total_normal_onm += (int) normalOnm;
00085 }
00086 }
00087
00088 void Facility::init_data() {
00089
00090
00091
00092
00093 update_parking(true);
00094 update_crime(true);
00095
00096
00097
00098
00099 maximum_debt_balance_as_a_percent_of_funds_balances = 0.5f;
00100 max_interest_payments_as_a_percent_of_operating_expenditures = 0.08f;
00101
00102 percent_gap_required_before_new_construction_is_considered = 0.1f;
00103 escalation_factor_for_deferrd_maintenance_per_year = 0.025f;
00104
00105
00106
00107 percent_project_funded_with_debt = 33.3f;
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120 float opReserve = (float) finance.this_year.asset_array[AC_OPERATING_RESERVE];
00121
00122 float availableFunds = float( opReserve
00123 + 0.5*( finance.this_year.asset_array[AC_ENDOWMENT]
00124 +finance.this_year.asset_array[AC_CAPITAL_RESERVE] )
00125 + 0.25 *finance.this_year.asset_array[AC_BUILDINGS]
00126 - finance.this_year.liability_array[AC_LIABILITY_TOTAL]);
00127
00128 availableFunds = max(0.0f,availableFunds);
00129
00130 total_debt_capacity[THIS_YEAR] = (int) min(
00131 (float)(maximum_debt_balance_as_a_percent_of_funds_balances * availableFunds),
00132 (float)(finance.projected_total_operating_expense.this_year.total * max_interest_payments_as_a_percent_of_operating_expenditures
00133 / (finance.long_term_debt_interest / 100.0f)) );
00134
00135 total_debt_capacity[THIS_YEAR] = max(0,total_debt_capacity[THIS_YEAR]);
00136
00137
00138 debt_limit[THIS_YEAR] = cur_debt_limit = int(total_debt_capacity[THIS_YEAR]);
00139
00140
00141 outstanding_debt_balance[THIS_YEAR] = (int)finance.this_year.liability_array[AC_GENERAL_PLANT_DEBT];
00142
00143 int beginCapitalReserve = int(finance.last_year.asset_array[AC_CAPITAL_RESERVE]);
00144
00145 min_capital_reserve_balance = 0.0f;
00146
00147 ratio_of_square_footage_to_benchmark[THIS_YEAR] = 1.0f;
00148
00149
00150
00151 cur_change_backlog = 0;
00152
00153
00154 begin_space_inventory();
00155
00156
00157
00158 finance.this_year.asset_array[AC_BUILDINGS] = finance.last_year.asset_array[AC_BUILDINGS];
00159 finance.this_year.asset_array[AC_CAPITAL_RESERVE] = finance.last_year.asset_array[AC_CAPITAL_RESERVE];
00160 finance.this_year.liability_array[AC_GENERAL_PLANT_DEBT] = finance.last_year.liability_array[AC_GENERAL_PLANT_DEBT];
00161
00162 finance.this_year.liability_array[AC_LIABILITY_TOTAL] = 0;
00163 for( int i=0 ; i<LIABILITY_ITEM_COUNT-1 ; i++ ) {
00164 finance.this_year.liability_array[AC_LIABILITY_TOTAL] += finance.this_year.liability_array[i];
00165 }
00166
00167 update_vars_monthly();
00168
00169
00170 onm_n_backlog_history[SECOND_H_THIS_YEAR-1] = onm_n_backlog_history[SECOND_H_THIS_YEAR];
00171
00172 calc_facility_staff_morale();
00173 }
00174
00175
00176
00177
00179
00180
00181 if ( ( info.game_day == 1 )
00182 && info.game_month == finance.fiscal_year_start_month ) {
00183
00184
00185
00186
00187
00188 update_history_yearly();
00189
00190 update_parking();
00191
00192 #if(GAME_VERSION>=200)
00193 #else
00194 begin_space_inventory();
00195 #endif
00196 }
00197
00198
00199 if ( info.game_day == 1 ) {
00200 update_crime();
00201
00202 update_vars_monthly();
00203
00204 calc_facility_staff_morale();
00205
00206
00207 if ( info.game_month == finance.fiscal_year_start_month ) {
00208 #if(GAME_VERSION>=200)
00209 #else
00210 run_new_construction();
00211 #endif
00212 }
00213 }
00214 }
00215
00216
00217
00218
00221
00222
00223 onm_n_backlog_history[FIRST_H_THIS_YEAR-1] = (int) finance.expense_array[AC_OPERATIONS_AND_MAINTENANCE].total;
00224
00225
00226 transfer_history[H_PREV_YEAR] = (int) finance.expense_array[AC_TRANSFER_TO_CAPITAL_RESERVE].total;
00227 gifts_to_facility[H_PREV_YEAR] = (int) development_office.last_year.facilities;
00228
00229
00230 onm_n_backlog_history[FIRST_H_THIS_YEAR] = (int) finance.projected_expense_array[AC_OPERATIONS_AND_MAINTENANCE].this_year.total;
00231
00232
00233 transfer_history[H_THIS_YEAR] = (int) finance.projected_expense_array[AC_TRANSFER_TO_CAPITAL_RESERVE].this_year.total;
00234
00235
00236 gifts_to_facility[H_THIS_YEAR] = (int) development_office.this_year.facilities;
00237
00238
00239
00240
00241 onm_n_backlog_history[FIRST_H_THIS_YEAR+1] = (int) finance.projected_expense_array[AC_OPERATIONS_AND_MAINTENANCE].next_year.total;
00242
00243
00244 transfer_history[H_NEXT_YEAR] = (int) finance.projected_expense_array[AC_TRANSFER_TO_CAPITAL_RESERVE].next_year.total;
00245 gifts_to_facility[H_NEXT_YEAR] = (int) development_office.this_year.facilities;
00246
00247 captial_reserve_expense[H_NEXT_YEAR] = captial_reserve_expense[H_THIS_YEAR];
00248 }
00249
00250
00251
00252
00256
00257 int h;
00258
00259
00260
00261
00262
00263 for ( h=0; h<HISTORY_YEAR_COUNT-1; h++) {
00264 ratio_of_square_footage_to_benchmark[h] = ratio_of_square_footage_to_benchmark[h+1];
00265
00266 total_debt_capacity[h] = total_debt_capacity[h+1];
00267 outstanding_debt_balance[h] = outstanding_debt_balance[h+1];
00268 debt_limit[h] = debt_limit[h+1];
00269
00270 construction_project_spending[h] = construction_project_spending[h+1];
00271
00272 transfer_history[h] = transfer_history[h+1];
00273 gifts_to_facility[h] = gifts_to_facility[h+1];
00274 captial_reserve_expense[h] = captial_reserve_expense[h+1];
00275 }
00276
00277 shift_history(onm_n_backlog_history, HISTORY_YEAR_COUNT2);
00278
00279
00280
00281 captial_reserve_expense[H_THIS_YEAR] = 0;
00282
00283
00284
00285
00286
00287 float availableFunds = (float) finance.get_available_funds();
00288
00289 total_debt_capacity[THIS_YEAR] = (int) min(
00290 (float)(maximum_debt_balance_as_a_percent_of_funds_balances * availableFunds),
00291 (float)(finance.projected_total_operating_expense.this_year.total * max_interest_payments_as_a_percent_of_operating_expenditures
00292 / (finance.long_term_debt_interest / 100.0f)) );
00293
00294 total_debt_capacity[THIS_YEAR] = max(0,total_debt_capacity[THIS_YEAR]);
00295
00296
00297
00298
00299 float inflationRate = (float) finance.inflation_rate / 100.0f;
00300 const float growth = float(1 + inflationRate + finance.construction_cost_growth/100.0f);
00301
00302 DepartmentInfo *deptInfo;
00303 GeneralDepartment* dept;
00304
00305 int deptCount = department_array.department_count;
00306 int totalActualSF = 0, totalNormalSF = 0, totalProjectedSF = 0, i;
00307
00308 for( i=0 ; i<=deptCount; i++ ) {
00309 if ( i ) {
00310 dept = (GeneralDepartment*) department_array[i];
00311
00312 deptInfo = (department_res.info_array + department_array[i]->department_id - 1);
00313 }
00314 else {
00315
00316 dept = &department_res.general_dept;
00317 deptInfo = &department_res.general_dept_info;
00318 }
00319
00320 totalActualSF += deptInfo->actual_sf;
00321 totalNormalSF += deptInfo->normal_sf;
00322 totalProjectedSF += dept->get_constructing_sf() + deptInfo->actual_sf;
00323
00324
00325
00326 float last1 = deptInfo->cost_growth;
00327 deptInfo->cost_growth = math.time_variation(last1, (deptInfo->cost_growth_last2), 1.4482f, -0.8011f, 0.003528950f) + 0.03f;
00328 deptInfo->cost_growth_last2 = last1;
00329
00330 deptInfo->replacement_cost = int( deptInfo->replacement_cost * (1+inflationRate+deptInfo->cost_growth) );
00331
00332 err_when(deptInfo->replacement_cost <= 0);
00333 }
00334
00335 #if(GAME_VERSION>=200)
00336
00337 int totalReplacementCost=0;
00338
00339 for( i=0 ; i<=deptCount; i++ ) {
00340 if ( i ) {
00341
00342 deptInfo = (department_res.info_array + department_array[i]->department_id - 1);
00343 }
00344 else {
00345
00346 deptInfo = &department_res.general_dept_info;
00347 }
00348
00349 totalReplacementCost += deptInfo->replacement_cost;
00350 }
00351
00352
00353 for( i=0 ; i<=deptCount; i++ ) {
00354 if ( i ) {
00355
00356 deptInfo = (department_res.info_array + department_array[i]->department_id - 1);
00357 }
00358 else {
00359
00360 deptInfo = &department_res.general_dept_info;
00361 }
00362
00363 deptInfo->replacement_cost = totalReplacementCost/deptCount;
00364 }
00365 #endif
00366
00367
00368
00369
00370 ratio_of_square_footage_to_benchmark[THIS_YEAR] = 1.0f;
00371 err_when(!totalActualSF);
00372
00373 for( i=0 ; i<=deptCount; i++ ) {
00374 if ( i ) {
00375 dept = (GeneralDepartment*) department_array[i];
00376 deptInfo = (department_res.info_array+department_array[i]->department_id - 1);
00377 }
00378 else
00379
00380 deptInfo = &department_res.general_dept_info;
00381
00382 float ratio_sf_to_benchmark = float(deptInfo->actual_sf) / deptInfo->normal_sf;
00383
00384 ratio_of_square_footage_to_benchmark[THIS_YEAR] *= (float) math.safe_pow(ratio_sf_to_benchmark, float(deptInfo->actual_sf) / totalActualSF);
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409 finance.this_year.asset_array[AC_BUILDINGS]
00410 = finance.this_year.asset_array[AC_BUILDINGS]
00411 - finance.this_year.asset_array[AC_BUILDINGS] / finance.building_life_for_calc_depreciation;
00412
00413 finance.this_year.asset_array[AC_CAPITAL_RESERVE] += development_office.last_year.facilities;
00414
00415 finance.this_year.liability_array[AC_GENERAL_PLANT_DEBT]
00416 = finance.this_year.liability_array[AC_GENERAL_PLANT_DEBT]
00417 - finance.this_year.liability_array[AC_GENERAL_PLANT_DEBT] * finance.debt_fraction_repaid_annually / 100.0f;
00418
00419 #if(GAME_VERSION>=200)
00420 facility_office.outstanding_debt_balance[THIS_YEAR] = finance.this_year.liability_array[AC_GENERAL_PLANT_DEBT];
00421 #endif
00422
00423 finance.this_year.liability_array[AC_LIABILITY_TOTAL] = 0;
00424 for( i=0 ; i<LIABILITY_ITEM_COUNT-1 ; i++ ) {
00425 finance.this_year.liability_array[AC_LIABILITY_TOTAL] += finance.this_year.liability_array[i];
00426 }
00427
00428
00429
00430 construction_project_spending[THIS_YEAR] = 0;
00431 cur_change_backlog = 0;
00432 }
00433
00434
00435
00436
00440
00441 DepartmentInfo *deptInfo;
00442 Department* dept;
00443
00444 int deptCount = department_array.department_count;
00445
00446
00447
00448
00449
00450 for( int i=1 ; i<=deptCount; i++ ) {
00451 dept = department_array[i];
00452 deptInfo = (department_res.info_array+dept->department_id - 1);
00453
00454
00455
00456
00457
00458
00459
00460 deptInfo->normal_sf = int(
00461 deptInfo->fixed_sf_per_dept
00462 + dept->course_array.course_enrollments[SEMINAR] * deptInfo->sf_per_course_enrollment_in_seminars
00463 + dept->course_array.course_enrollments[GENERAL] * deptInfo->sf_per_course_enrollment_in_general_courses
00464 + dept->course_array.course_enrollments[CLASS_WITH_BREAKOUT] * deptInfo->sf_per_course_enrollment_in_lecture_courses
00465 + deptInfo->sf_per_faculty * dept->faculty_array.faculty_count
00466
00467 + deptInfo->sf_per_research_dollar * dept->total_research_dollar /1000);
00468
00469
00470 #if(GAME_VERSION>=200)
00471 if ( info.prerun_year && info.game_year == 1 ) {
00472 deptInfo->actual_sf = (int)( (float)deptInfo->normal_sf * math.get_random_snd(1.1f, PSCH_SD(0.25f)) );
00473 }
00474 #else
00475 if ( deptInfo->actual_sf <= 0) {
00476
00477
00478
00479 deptInfo->actual_sf = m.fmax(10, (int) math.get_random_snd(float(deptInfo->normal_sf), PSCH_SD(deptInfo->normal_sf * 0.005f)));
00480 }
00481 #endif
00482 }
00483
00484
00485
00486
00487
00488 deptInfo = &department_res.general_dept_info;
00489
00490 int tmp;
00491
00492
00493 tmp = int(finance.total_operating_expense.total - finance.expense_array[AC_ACADEMIC_DEPARTMENTS].total - finance.expense_array[AC_SPONSORED_RESEARCH_EXPENSE].total);
00494 tmp = max(0,tmp);
00495
00496 deptInfo->normal_sf = int(deptInfo->fixed_sf_per_dept + tmp * deptInfo->sf_per_dollar_of_central_exp);
00497
00498 #if(GAME_VERSION>=200)
00499 if ( info.prerun_year && info.game_year == 1 ) {
00500 deptInfo->actual_sf = (int)( (float)deptInfo->normal_sf * math.get_random_snd(1.1f, PSCH_SD(0.25f)) );
00501 }
00502 #else
00503 if ( deptInfo->actual_sf <= 0 ) {
00504 deptInfo->actual_sf = m.fmax(10, (int) math.get_random_snd(float(deptInfo->normal_sf), PSCH_SD(deptInfo->normal_sf * 0.005f)));
00505 }
00506 #endif
00507 }
00508
00509
00510
00511
00513
00514
00515
00516
00517
00518 DepartmentInfo *deptInfo;
00519 GeneralDepartment* dept;
00520
00521 int deptCount = department_array.department_count;
00522
00523 float normalOnm;
00524 int newSF, projectExpense, projectExpenseTotal = 0;
00525
00526 int totalActualSF = 0, totalNormalSF = 0, totalProjectedSF = 0;
00527
00528 total_normal_onm = 0;
00529
00530
00531
00532 for( int i=0 ; i<=deptCount; i++ ) {
00533 if (i) {
00534 dept = (GeneralDepartment*) department_array[i];
00535 deptInfo = (department_res.info_array+department_array[i]->department_id - 1);
00536 }
00537 else {
00538
00539 dept = &department_res.general_dept;
00540 deptInfo = &department_res.general_dept_info;
00541 }
00542
00543
00544
00545 dept->next_month_construction(newSF, projectExpense);
00546
00547
00548
00549 deptInfo->actual_sf += newSF;
00550 projectExpenseTotal += projectExpense;
00551
00552
00553 normalOnm = (deptInfo->actual_sf * deptInfo->normal_onm_cost / 1000.0f);
00554 total_normal_onm += (int) normalOnm;
00555
00556 totalActualSF += deptInfo->actual_sf;
00557 totalNormalSF += deptInfo->normal_sf;
00558 totalProjectedSF += dept->get_constructing_sf() + deptInfo->actual_sf;
00559
00560 err_when( deptInfo->normal_sf<=0 || deptInfo->actual_sf<=0 || normalOnm<=0 );
00561 }
00562
00563
00564 shift_history(normal_area, HISTORY_MONTH_COUNT);
00565 shift_history(actual_area, HISTORY_MONTH_COUNT);
00566 shift_history(projected_area, HISTORY_MONTH_COUNT);
00567
00568 normal_area[THIS_MONTH] = totalNormalSF;
00569 actual_area[THIS_MONTH] = totalActualSF;
00570 projected_area[THIS_MONTH] = totalProjectedSF;
00571
00572
00573
00574
00575
00576
00577
00578
00579 int tmp = int(math.get_random_snd(0.0f, PSCH_SD(0.05f * float(total_normal_onm)) ));
00580 int beginBacklog = total_normal_onm + ( (tmp > 0) ? tmp : 0);
00581
00582 #if(GAME_VERSION>=200) // remove stage1_revenue, stage1_expense, stage2_expense
00583
00584 float buget_monthly; {
00585 double cons1 = (1 + finance.inflation_rate/100.0 + finance.expense_policy_array[PL_STAFF_SALARY_INCREASES].result_value / 100.0);
00586 double cons2 = (1 + finance.inflation_rate/100.0 + finance.other_expense_growth/100.0);
00587 double computed_growthrate = finance.cost_rise_policy_array[AC_OPERATIONS_AND_MAINTENANCE].result_value;
00588 double base_value = cons1 * finance.expense_array[AC_OPERATIONS_AND_MAINTENANCE].staff + cons2 * finance.expense_array[AC_OPERATIONS_AND_MAINTENANCE].other;
00589 double change_value = base_value * computed_growthrate / 100.0;
00590 double new_value = (change_value + base_value );
00591 buget_monthly = float(new_value / 12.0f);
00592 }
00593
00594 #else
00595 float buget_monthly = float(finance.stage2_expense[S2_OPERATIONS_AND_MAINTENANCE].new_value / 12.0f);
00596 #endif
00597
00598 cur_change_backlog = int(
00599 beginBacklog * escalation_factor_for_deferrd_maintenance_per_year / 12.0f
00600 - total_normal_onm / 12.0f - buget_monthly);
00601
00602
00603 onm_n_backlog_history[SECOND_H_THIS_YEAR] = max(0, beginBacklog + cur_change_backlog);
00604 onm_n_backlog_history[SECOND_H_THIS_YEAR+1] = onm_n_backlog_history[SECOND_H_THIS_YEAR];
00605
00606
00607 update_history_sub();
00608 }
00609
00610
00611
00612
00616
00617
00618
00619
00620
00621
00622
00623 debt_limit[THIS_YEAR] = cur_debt_limit;
00624
00625
00626 int e44;
00627 e44 = outstanding_debt_balance[THIS_YEAR] = (int)finance.this_year.liability_array[AC_GENERAL_PLANT_DEBT];
00628
00629 int maxNewDebt = int(min(total_debt_capacity[THIS_YEAR], debt_limit[THIS_YEAR])
00630 - e44 + e44 * finance.debt_fraction_repaid_annually / 100.0f);
00631
00632 int beginCapitalReserve = int(finance.last_year.asset_array[AC_CAPITAL_RESERVE]);
00633
00634
00635 int interestReceived = int(beginCapitalReserve * (finance.inflation_rate + finance.short_term_debt_interest ) / 100.0f );
00636
00637 int transferFromBudget = int(finance.budget_expense_array[AC_TRANSFER_TO_CAPITAL_RESERVE].total);
00638
00639
00640
00641 if ( transferFromBudget < 0 )
00642 transferFromBudget = 0;
00643
00644
00645
00646 int availableCapitalReserveFunds
00647 = beginCapitalReserve + interestReceived + transferFromBudget - min_capital_reserve_balance;
00648
00649
00650
00651 min_capital_reserve_balance = 0.0f;
00652
00653
00654 if ( availableCapitalReserveFunds < 0 )
00655 availableCapitalReserveFunds = 0;
00656
00657
00658
00659
00660
00661 DepartmentInfo *deptInfo;
00662 GeneralDepartment* dept;
00663
00664 int deptCount = department_array.department_count;
00665 float percentGap;
00666 int sfGap;
00667 int newSquareFoot;
00668 float actualInvest,
00669 actualDrawOnCapitalReserve,
00670 totalActualInvest = 0,
00671 totalAdditionalDebt = 0,
00672 totalRequiredDrawOnCapitalReserve = 0;
00673 #if(GAME_VERSION>=200)
00674 int totalAvailableSpace=0;
00675 #endif
00676
00677
00678
00679 for( int i=0 ; i<=deptCount; i++ ) {
00680 if ( i ) {
00681 dept = department_array[i];
00682 deptInfo = (department_res.info_array+department_array[i]->department_id - 1);
00683 }
00684 else {
00685
00686 dept = &department_res.general_dept;
00687 deptInfo = &department_res.general_dept_info;
00688 }
00689
00690 sfGap = max(0, deptInfo->normal_sf - deptInfo->actual_sf - dept->get_constructing_sf());
00691
00692 #if(GAME_VERSION>=200)
00693 totalAvailableSpace += sfGap;
00694 #endif
00695
00696 percentGap = float(sfGap) / deptInfo->normal_sf;
00697
00698 deptInfo->invest_close_gap = ( percentGap > percent_gap_required_before_new_construction_is_considered )
00699 ? (float(sfGap) * deptInfo->replacement_cost / 1000) : 0;
00700
00701 deptInfo->additional_debt = (deptInfo->invest_close_gap * float(percent_project_funded_with_debt) / 100.0f );
00702 totalAdditionalDebt += deptInfo->additional_debt;
00703
00704 err_when(deptInfo->invest_close_gap<0 || deptInfo->additional_debt < 0);
00705 err_when(deptInfo->invest_close_gap < deptInfo->additional_debt );
00706 }
00707
00708 total_actual_new_debt = 0;
00709
00710
00711 float maxDebt = max(0.0f,min((float)maxNewDebt, totalAdditionalDebt));
00712
00713 for( i=0 ; i<=deptCount; i++ ) {
00714 if ( i ) {
00715 dept = department_array[i];
00716 deptInfo = (department_res.info_array+department_array[i]->department_id - 1);
00717 }
00718 else
00719
00720 deptInfo = &department_res.general_dept_info;
00721
00722 if ( totalAdditionalDebt ) {
00723
00724 deptInfo->actual_new_debt = (float(deptInfo->additional_debt) * float(maxDebt) / totalAdditionalDebt);
00725 total_actual_new_debt += deptInfo->actual_new_debt;
00726 err_when(deptInfo->actual_new_debt < 0 );
00727 }
00728 else
00729 deptInfo->actual_new_debt = 0;
00730
00731 deptInfo->required_draw_on_capital_reserve = deptInfo->invest_close_gap - deptInfo->actual_new_debt;
00732
00733
00734 if ( deptInfo->required_draw_on_capital_reserve < 0 ) {
00735 deptInfo->actual_new_debt = deptInfo->invest_close_gap;
00736
00737 total_actual_new_debt += deptInfo->required_draw_on_capital_reserve;
00738 deptInfo->required_draw_on_capital_reserve = 0;
00739 }
00740 else
00741 totalRequiredDrawOnCapitalReserve += deptInfo->required_draw_on_capital_reserve;
00742
00743 err_when(deptInfo->required_draw_on_capital_reserve < 0);
00744
00745 err_when(deptInfo->invest_close_gap >= 10
00746 && deptInfo->invest_close_gap < deptInfo->actual_new_debt + deptInfo->required_draw_on_capital_reserve - 10 );
00747 }
00748
00749 err_when(totalAdditionalDebt < 0 || totalRequiredDrawOnCapitalReserve < 0 || total_actual_new_debt < 0);
00750
00751
00752 bool newConstructionAdded = false;
00753
00754 #if(GAME_VERSION>=200)
00755 float fundedByDebt = facility_office.debt_spinner_var1/100;
00756 int investmentRequirement = int(facility_office.spinner_var4*department_res.general_dept_info.replacement_cost);
00757
00758 int facilityReserveRequired = investmentRequirement*(1-fundedByDebt);
00759
00760 int debtRequirement = investmentRequirement*fundedByDebt;
00761 #endif
00762
00763 for( i=0 ; i<=deptCount; i++ ) {
00764 if ( i ) {
00765 dept = department_array[i];
00766 deptInfo = (department_res.info_array+department_array[i]->department_id - 1);
00767 }
00768 else {
00769
00770 dept = &department_res.general_dept;
00771 deptInfo = &department_res.general_dept_info;
00772 }
00773
00774
00775 if ( totalRequiredDrawOnCapitalReserve && availableCapitalReserveFunds ) {
00776 float avaltRatio = min( 1.0f, availableCapitalReserveFunds / totalRequiredDrawOnCapitalReserve );
00777
00778 actualDrawOnCapitalReserve = float(deptInfo->required_draw_on_capital_reserve) * avaltRatio;
00779 }
00780 else
00781 actualDrawOnCapitalReserve = 0;
00782
00783 actualDrawOnCapitalReserve = min( actualDrawOnCapitalReserve, deptInfo->invest_close_gap - deptInfo->actual_new_debt);
00784
00785 actualInvest = actualDrawOnCapitalReserve + deptInfo->actual_new_debt;
00786 totalActualInvest += actualInvest;
00787
00788 #if(GAME_VERSION>=200)
00789 if ( totalAvailableSpace != 0 )
00790 newSquareFoot = facility_office.spinner_var4*1000*max(0, deptInfo->normal_sf - deptInfo->actual_sf - dept->get_constructing_sf())/totalAvailableSpace;
00791 else
00792
00793 newSquareFoot = facility_office.spinner_var4*1000/(deptCount+1);
00794 #else
00795 newSquareFoot = int(actualInvest * 1000 / deptInfo->replacement_cost);
00796 #endif
00797
00798 err_when(newSquareFoot<0 || deptInfo->replacement_cost <=0);
00799 #if(GAME_VERSION>=200)
00800 #else
00801 err_when(newSquareFoot > 1.5 * deptInfo->normal_sf);
00802 #endif
00803
00804
00805
00806 #if(GAME_VERSION>=200)
00807 if ( newSquareFoot > 0 )
00808 #else
00809 if ( newSquareFoot >0 && actualInvest >0 )
00810 #endif
00811 {
00812
00813 construction_project_spending[THIS_YEAR] += actualInvest;
00814 #if(GAME_VERSION>=200)
00815 #else
00816 captial_reserve_expense[H_THIS_YEAR] += actualDrawOnCapitalReserve;
00817 #endif
00818
00819
00820 dept->add_construction(newSquareFoot, max(1,(int)actualInvest));
00821 newConstructionAdded = true;
00822 }
00823
00824 err_when(actualDrawOnCapitalReserve < 0 || deptInfo->actual_new_debt < 0);
00825 }
00826
00827 #if(GAME_VERSION>=200)
00828 captial_reserve_expense[H_THIS_YEAR] += facilityReserveRequired;
00829 #endif
00830
00831
00832
00833 if( captial_reserve_expense[H_NEXT_YEAR] == 0 )
00834 captial_reserve_expense[H_NEXT_YEAR] = captial_reserve_expense[H_THIS_YEAR];
00835
00836
00837
00838 if ( newConstructionAdded ) {
00839 if ( totalActualInvest > 0 )
00840 finance.this_year.asset_array[AC_BUILDINGS]
00841 = finance.this_year.asset_array[AC_BUILDINGS] + totalActualInvest;
00842
00843 #if(GAME_VERSION>=200)
00844 if ( facilityReserveRequired > 0 ) {
00845
00846 finance.this_year.asset_array[AC_CAPITAL_RESERVE] -= captial_reserve_expense[H_THIS_YEAR];
00847
00848 }
00849 #else
00850 if ( totalRequiredDrawOnCapitalReserve > 0 ) {
00851
00852 finance.this_year.asset_array[AC_CAPITAL_RESERVE] -= captial_reserve_expense[H_THIS_YEAR];
00853
00854 }
00855 #endif
00856
00857 #if(GAME_VERSION>=200)
00858 if ( debtRequirement > 0 ) {
00859
00860 finance.this_year.liability_array[AC_GENERAL_PLANT_DEBT] += debtRequirement;
00861 facility_office.outstanding_debt_balance[THIS_YEAR] = finance.this_year.liability_array[AC_GENERAL_PLANT_DEBT];
00862 }
00863 #else
00864 if ( total_actual_new_debt > 0 )
00865 finance.this_year.liability_array[AC_GENERAL_PLANT_DEBT] += total_actual_new_debt;
00866 #endif
00867 }
00868
00869 finance.this_year.liability_array[AC_LIABILITY_TOTAL] = 0;
00870 for( i=0 ; i<LIABILITY_ITEM_COUNT-1 ; i++ ) {
00871 finance.this_year.liability_array[AC_LIABILITY_TOTAL] += finance.this_year.liability_array[i];
00872 }
00873
00874
00875
00876 #if(GAME_VERSION>=200)
00877
00878 #else
00879
00880 double bank_deposit_rate_per_month = finance.inflation_rate + .01;
00881
00882 finance.this_year.asset_array[AC_CAPITAL_RESERVE] += bank_deposit_rate_per_month * 12 * finance.this_year.asset_array[AC_CAPITAL_RESERVE];
00883 #endif
00884 }
00885
00886
00887
00888
00889 void Facility::calc_facility_staff_morale() {
00890 const int VAR_COUNT = 3;
00891 int i;
00892 float input[VAR_COUNT];
00893 memset(input, 0, sizeof(input));
00894
00895
00896 input[0] = player_school.staff_morale;
00897
00898
00899 input[1] = 100*float(onm_n_backlog_history[SECOND_H_THIS_YEAR]) / float(finance.this_year.asset_array[AC_BUILDINGS]);
00900
00901
00902 DepartmentInfo *deptInfo;
00903 int deptCount = department_array.department_count;
00904 total_invest_close_gap = 0;
00905
00906 for( i=0 ; i<=deptCount; i++ ) {
00907 if ( i ) {
00908 deptInfo = (department_res.info_array+department_array[i]->department_id - 1 );
00909 }
00910 else {
00911 deptInfo = &department_res.general_dept_info;
00912 }
00913
00914 total_invest_close_gap += deptInfo->invest_close_gap;
00915 }
00916
00917 input[2] = 100*float(total_invest_close_gap) / float(finance.this_year.asset_array[AC_BUILDINGS]);
00918
00919 err_when( finance.this_year.asset_array[AC_BUILDINGS] <= 0 );
00920
00921
00922 input[1] = math.dual_response_func(0,60.74f,100,-7.15f,-5.94f,16.41f,3.95f, input[1]);
00923 input[2] = math.dual_response_func(0,68.17f,100,-13.40f,-7.24f,20.54f,4.32f, input[2]);
00924
00925 float weight[VAR_COUNT] = {0.50f, 0.30f, 0.2f, };
00926
00927 float newValue = 0;
00928 for(i=0; i<VAR_COUNT; i++)
00929 newValue += weight[i] * input[i];
00930
00931
00932 facility_staff_morale = max(0.0f,min(100.0f,player_school.latency_func( 0.1f, facility_staff_morale, newValue)));
00933
00934
00935 facility_staff_morale *= (float) finance.cost_rise_policy_array[PL_OPERATIONS_AND_MAINTENANCE].penalty_multiplier1;
00936
00937
00938 facility_staff_morale = max(0.0f,min(100.0f,facility_staff_morale));
00939 }
00940
00941
00942
00943
00945
00946
00947
00948
00949 int demandVar[COEF_COUNT];
00950 int totalDemand = 0;
00951
00952 demandVar[0] = department_array.faculty_level_history[FACULTY_RANK_LEVEL_COUNT][THIS_YEAR];
00953 demandVar[1] = int(finance.total_expense.staff / 65000000);
00954
00955 for (int i=0; i<MAX_STUDENT_LEVEL; i++)
00956 demandVar[i+2] = department_array.student_level_history[i][THIS_YEAR];
00957
00958 for (int x=0; x<COEF_COUNT; x++)
00959 totalDemand += int(parking_demand_coef[player_school.campus_environment][x] * demandVar[x]);
00960
00961
00962
00963 if ( init ) {
00964 const float meanByEnvir[ENVIRONMENT_COUNT] = { 1.0f, 1.1f, 1.2f };
00965 float mean = meanByEnvir[player_school.campus_environment];
00966
00967
00968 cur_parking_supply = int(totalDemand * math.get_random_snd(mean, PSCH_SD(mean*0.1f)));
00969 projected_parking_supply = cur_parking_supply;
00970
00971 farout_capacity = int(cur_parking_supply * math.get_random_snd(1.3f , PSCH_SD(0.1f)));
00972 }
00973
00974 if ( !init && totalDemand > cur_parking_supply ) {
00975 if ( player_school.campus_environment == RURAL )
00976 cur_parking_supply = totalDemand;
00977 else if ( player_school.campus_environment == SUBURBAN && farout_capacity > 0 ) {
00978 int newSpace = min(farout_capacity, totalDemand - cur_parking_supply);
00979
00980 farout_capacity -= newSpace;
00981 cur_parking_supply += newSpace;
00982 }
00983 else {
00984
00985
00986
00987 finance.this_year.asset_array[AC_CAPITAL_RESERVE] -= 30 * (totalDemand - cur_parking_supply);
00988
00989 projected_parking_supply = totalDemand;
00990 cur_parking_supply = projected_parking_supply;
00991
00992
00993 }
00994 }
00995
00996 shift_history(parking_demand, HISTORY_YEAR_COUNT);
00997 shift_history(parking_supply, HISTORY_YEAR_COUNT);
00998
00999 parking_demand[THIS_YEAR] = cur_parking_supply;
01000 parking_supply[THIS_YEAR] = totalDemand;
01001
01002 if ( init ) {
01003 err_when(totalDemand <= 0);
01004 err_when(cur_parking_supply <= 0);
01005
01006 for (i = THIS_YEAR; i>=THIS_YEAR-1; i--) {
01007 parking_demand[i-1] = parking_demand[i];
01008 parking_supply[i-1] = parking_supply[i];
01009 }
01010 }
01011 }
01012
01013
01014
01015
01017
01018 static float initAdminRatio = float(finance.projected_expense_array[AC_ADMINISTRATION_N_OTHER_OPERATING_EXPENSE].this_year.total / finance.projected_total_operating_expense.this_year.total ) ;
01019
01020
01021
01022
01023
01024
01025 static float currCrime=0;
01026 int i;
01027
01028
01029 const int VAR_COUNT = 4;
01030 float input[VAR_COUNT];
01031
01032
01033 const int remap[ENVIRONMENT_COUNT]={3,2,1};
01034 input[0] = 25 * (float) remap[player_school.campus_environment];
01035
01036
01037 input[1] = (float) ((finance.projected_expense_array[AC_ADMINISTRATION_N_OTHER_OPERATING_EXPENSE].this_year.total / finance.projected_total_operating_expense.this_year.total ) / initAdminRatio);
01038
01039
01040 input[2] = player_school.sub_score[S_STUDENT_MORALE][THIS_MONTH];
01041
01042
01043 input[3] = player_school.staff_morale;
01044
01045
01046 input[1] = math.single_response_func(1,100,1.900f, 1.047f, input[1]);
01047 input[2] = math.dual_response_func(1, 50.1f, 100, -40.21f, -24.36f, 69.78f, 20.19f, input[2]);
01048 input[3] = math.dual_response_func(1, 51.5f, 100, -51.33f, -27.54f, 62.25f, 16.38f, input[3]);
01049
01050 const float weight[VAR_COUNT] = { 0.40f,0.35f,0.15f,0.10f };
01051 float newValue=0;
01052
01053 for (i=0;i<VAR_COUNT;i++)
01054 newValue += weight[i] * input[i];
01055
01056 currCrime = player_school.latency_func(0.1f, newValue, currCrime);
01057
01058
01059
01060
01061 currCrime = m.fmin(100.0f, m.fmax(0.0f,math.get_random_snd(currCrime, PSCH_SD(currCrime * 0.075f))));
01062
01063 shift_history(crime_index, HISTORY_MONTH_COUNT);
01064 crime_index[THIS_MONTH] = (char) player_school.latency_func(0.5f, currCrime, crime_index[THIS_MONTH]);
01065
01066 if ( init ) {
01067 for (i = THIS_MONTH; i>=THIS_MONTH-1; i--) {
01068 crime_index[i-1] = crime_index[i];
01069 }
01070 }
01071 }
01072
01073
01074
01075
01076 #if(GAME_VERSION>=200)
01077
01078 void Facility::save_initial_data() {
01079 initial_total_invest_close_gap = total_invest_close_gap;
01080
01081
01082
01083 initial_captial_reserve_expense = captial_reserve_expense[H_PREV_YEAR];
01084 initial_crime_index = crime_index[THIS_MONTH];
01085 initial_normal_area = normal_area[THIS_MONTH];
01086 initial_actual_area = actual_area[THIS_MONTH];
01087 initial_projected_area = projected_area[THIS_MONTH];
01088 }
01089
01090
01091 #endif
01092