/* * Copyright (C) 2003 Tim Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include "utils.h" #include "player.h" struct balance_item balance_sheet_items[] = { {INCOME_INTEREST, "INTEREST", 0}, {INCOME_RENT, "RENT", 0}, {INCOME_REVENUE, "REVENUE", 0}, {INCOME_LAND, "LAND_SALES", 1}, {INCOME_TAX, "TAX", 0}, {BORROW, "BORROW", 1}, {COST_LAND, "LAND_PURCHASE", 1}, {COST_BUILD, "BUILD", 1}, {COST_UPKEEP, "UPKEEP", 0}, {COST_SALARY, "SALARY", 0}, {COST_DEBT, "DEBT_PAYMENTS", 0}, {INCOME_NUMTYPES, NULL, 0} }; typedef struct loan_s { struct loan_s *next; int total; int term; int principal; int monthly_payment; int payments_made; float rate; } loan_t; struct player_s { int playernum; char name[100]; double money; double income[RANGE_NUMRANGES][INCOME_NUMTYPES]; loan_t *loans; }; static player_t *players[MAX_NUM_PLAYERS]; int player_new(char *name, player_t **player) { player_t *ret; ret = calloc(sizeof(player_t), 1); if (!ret) return -1; strncpy(ret->name, name, sizeof(ret->name)-1); ret->playernum = -1; *player = ret; return 0; } int player_setopennumber(player_t *player) { int i; for (i = 1; i < MAX_NUM_PLAYERS; i++) { if (players[i] == NULL) { players[i] = player; player->playernum = i; return 0; } } return -1; } #if 0 static char * type_to_string(income_types type) { switch(type) { case INCOME_INTEREST: return "Interest"; case INCOME_RENT: return "Rent"; case INCOME_REVENUE: return "Revenue"; case INCOME_LAND: return "Land Sale"; case BORROW: return "Borrow"; case COST_LAND: return "Land Purchase"; case COST_BUILD: return "Building"; case COST_UPKEEP: return "Upkeep"; case COST_SALARY: return "Salary"; case COST_DEBT: return "Debt payments"; case INCOME_NUMTYPES: return "Invalid Type"; } return "Invalid Type"; } #endif /* 0 */ int player_isactive(int number) { if (players[number] == NULL) return 0; return 1; } player_t *player_get(int number) { return players[number]; } int player_getnum(player_t *player) { return player->playernum; } void player_setnumber(player_t *player, int number) { player->playernum = number; players[number] = player; } int player_getmoney(player_t *player) { return (int)player->money; } int player_canafford(player_t *player, int amount) { if (player->money < amount) { return 0; } return 1; } void player_reducemoney(player_t *player, income_types type, float amount) { player_reducemoney_num(player->playernum, type, amount); } void player_reducemoney_num(int playernum, income_types type, float amount) { if ((playernum <= 0) || (playernum > MAX_NUM_PLAYERS)) return; if (!players[playernum]) return; players[playernum]->income[RANGE_CURRENT_MONTH][type] -= amount; players[playernum]->income[RANGE_CURRENT_YEAR][type] -= amount; players[playernum]->income[RANGE_ALLTIME][type] -= amount; players[playernum]->money -= amount; /* xxx printf("%s spent $%.2f on %s\n", players[playernum]->name, amount, type_to_string(type));*/ } void player_addmoney(player_t *player, income_types type, float amount) { player_addmoney_num(player->playernum, type, amount); } void player_addmoney_num(int playernum, income_types type, float amount) { if ((playernum <= 0) || (playernum > MAX_NUM_PLAYERS)) return; if (!players[playernum]) return; players[playernum]->income[RANGE_CURRENT_MONTH][type] += amount; players[playernum]->income[RANGE_CURRENT_YEAR][type] += amount; players[playernum]->income[RANGE_ALLTIME][type] += amount; players[playernum]->money += amount; /* xxx printf("%s received $%.2f from %s\n", players[playernum]->name, amount, type_to_string(type));*/ } static void player_clearout_month(int playernum) { int i; player_t *player = players[playernum]; if (!player) return; for (i = 0; i < INCOME_NUMTYPES; i++) { player->income[RANGE_LAST_MONTH][i] = player->income[RANGE_CURRENT_MONTH][i]; player->income[RANGE_CURRENT_MONTH][i] = 0; } } static void player_clearout_year(int playernum) { int i; player_t *player = players[playernum]; if (!player) return; for (i = 0; i < INCOME_NUMTYPES; i++) { player->income[RANGE_LAST_YEAR][i] = player->income[RANGE_CURRENT_YEAR][i]; player->income[RANGE_CURRENT_YEAR][i] = 0; } } void players_clearout_month(void) { int i; for (i = 1; i < MAX_NUM_PLAYERS; i++) { player_clearout_month(i); } } void players_clearout_year(void) { int i; for (i = 1; i < MAX_NUM_PLAYERS; i++) { player_clearout_year(i); } } void player_setmoney(player_t *player, int number) { player->money = number; } void player_delete(player_t *player) { /* * Remove from used player list */ if (player->playernum > 0) { players[ player->playernum ] = NULL; } free(player); } int player_getincometype(player_t *player, income_range_t range, income_types type) { return player->income[range][type]; } static int loan_monthly_payment(float total, float rate, int term) { float top; float bot; /* * R = (P*I/12)/(1 - 1/((1+I/12)^N)) */ top = total * rate/12.0; bot = 1.0 - 1.0/(pow(1+rate/12.0,term)); return top/bot; } void player_addloan(player_t *player, int amount, int term, float rate) { loan_t *newloan; newloan = calloc(1, sizeof(loan_t)); if (!newloan) { printf("Error allocating loan\n"); return; } newloan->total = amount; newloan->principal = amount; newloan->term = term; newloan->rate = rate; newloan->monthly_payment = loan_monthly_payment(amount, rate, term); newloan->next = player->loans; player->loans = newloan; player_addmoney(player, BORROW, amount); } int player_total_borrowed(player_t *player) { int amount = 0; loan_t *loan = player->loans; while (loan) { amount += loan->principal; loan = loan->next; } return amount; } extern int player_payoff_loan(player_t *player, int num) { loan_t *loan = player->loans; loan_t *prev = NULL; int i; int cost; for (i = 0; i < num; i++) { prev = loan; loan = loan->next; } cost = loan->principal; if (!player_canafford(player, cost)) { return -1; } player_reducemoney(player, COST_DEBT, cost); /* * remove loan */ if (prev) { prev->next = loan->next; } else { player->loans = loan->next; } free(loan); return 0; } void player_servicedebt(player_t *player) { loan_t *loan = player->loans; loan_t *prev = NULL; while (loan) { int payment = loan->monthly_payment; int interest = loan->principal * (loan->rate/12.0); loan_t *next = loan->next; player_reducemoney(player, COST_DEBT, payment); loan->principal -= (payment - interest); loan->payments_made ++; if (loan->principal <= 0) { /* * remove loan */ if (prev) { prev->next = next; } else { player->loans = next; } free(loan); } else { prev = loan; } loan = next; } } int is_one_time(char *str) { int i; for (i = 0; i < INCOME_NUMTYPES; i++) { struct balance_item *item = &balance_sheet_items[i]; if (strcasecmp(str, item->string) == 0) { return item->is_one_time; } } return 0; } void player_loans_enumerate(player_t *player, player_loan_iterate_callback *cb, void *rock) { loan_t *loan = player->loans; int num = 0; while (loan) { cb(player, num, loan->total, loan->term, loan->payments_made, loan->rate, rock); loan = loan->next; num++; } } char * player_getname(int num) { player_t *p; if (num == 0) return _("General population"); p = players[num]; if (p) { return p->name; } else { return _("Unknown player"); } } int player_lastmonth_profit(player_t *player) { int i; int profit = 0; for (i = 0; i < INCOME_NUMTYPES; i++) { struct balance_item *item = &balance_sheet_items[i]; if (!is_one_time(item->string)) { profit += player->income[RANGE_LAST_MONTH][i]; } } return profit; }