inherit "/std/shops/auction_house"; #include <housing.h> #include <money.h> #include <move_failures.h> #include <room/auction.h> #include <nomic_system.h> #include <morpork.h> #define AUCTION_LENGTH (3600*24*5) #define NEW_AGREEMENT_COST 4000 #define REAL_ESTATE_NEW_LOT_BIDDING "new_low_bidding" private nosave string* _areas; private nosave string _city; private nosave string _language; int add_house(string house); int check_can_bid(object person, class auction which, int bid_amount); void create() { _areas = ({ }); _city = "Ankh-Morpork"; _language = "morporkian"; ::create(); add_help_file("real_estate"); } /* create() */ void reset() { call_out("after_reset", 10); } /** * This method adds in an area to which the real estate office will look * for houses. * @param area the area to look in */ void add_housing_area(string area) { _areas += ({ area }); } /* add_housing_area() */ /** * This method returns all the areas in which the real estate office will * look for houses. * @return the areas to look for houses */ string* query_housing_areas() { return _areas; } /* query_housing_areas() */ /** * This runs through the list of vacant houses and checks to see if it * should add them up for auction or not. */ void after_reset() { string house; string *available; int i; string area; // Find available houses and start an auction for them. foreach (area in _areas) { available = HOUSING->query_vacant(area); if (sizeof(available)) { i = 1; foreach(house in available) { call_out("add_house", i++, house); } } } } /** * Add a house for auction. * @string house the path of the house * @return 1 on success, 0 on failure */ int add_house(string house) { object agreement; string text; int tim; //Don't auction houses that don't really exist if (member_array(house, keys(HOUSING->query_houses())) == -1) { return 0; } // Sanity check to make sure houses are only listed once. if(lower_case(HOUSING->query_owner(house)) != "for sale") { log_file("REAS", ctime(time()) + ": attempt to add house %s that's " "not for sale.\n", house); return 0; } // Reset information about the house. HOUSING->set_rent(house, 0); agreement = clone_object(AGREEMENT); agreement->set_city(_city); agreement->set_language(_language); agreement->set_house(house); text = HOUSING->query_address(house); tim = query_last_auction_finish_time(); if (tim + 60 * 60 < time() + query_auction_times()["very long"]) { tim = 0; } else { tim = tim + 60 * 60 - time(); } if (add_item_to_auction(({ agreement }), text, 400, "Patrician", tim, "housing_auction", house)) { HOUSING->set_under_offer(house); broadcast_shop_event(REAL_ESTATE_NEW_LOT_BIDDING, this_player(), house); log_file("REAS", ctime(time()) + ": Added house %s\n", house); return 1; } } /** * This function is called during the various phases of the housing * auction. When each phase ends this method is called and anything * that needs to be done for the end of the phase is sorted out. * @param event_type the event that has finished * @param auct the auction that just finished * @param house the path of the house being auctioned * @param buyer the buyer of the house (if sold) * @param cost how much the house costs * @param obs the things that were sold (rental agreementsin this case) */ void housing_auction(int event_type, class auction auct, string house, string buyer, int cost, object *obs) { object book; //If we didn't sell it with the first reserve price, //try again with a smaller one. If we did sell it, //set the new owner! switch (event_type) { case AUCTION_WITHDRAW_PHASE: // Mark the house as For Sale again. if(lower_case(HOUSING->query_owner(house)) != "under offer") { write("House is not currently under offer!\n"); log_file("REAS", ctime(time()) + ": attempted to withdraw %s when it " "was not 'Under Offer'.\n", house); } else { HOUSING->set_for_sale(house); log_file("REAS", ctime(time()) + ": %s back to For Sale.\n", house); } break; case AUCTION_CLAIM_PHASE: HOUSING->set_owner(house, buyer); HOUSING->set_value(house, cost); obs[0]->set_city(_city); obs[0]->set_language(_language); obs[0]->set_house(house); log_file("REAS", ctime(time()) + ": %O sold to %O for %O.\n", house, buyer, MONEY_HAND->money_value_string(cost, query_property("place"))); //Throw in a copy of the home owners guide. book = clone_object(BOOK); if (book) { if (book->move(this_player()) != MOVE_OK) { book->move(this_object()); } } write("A nice new house owner's guide pops up for you.\n"); break; } } /** * Request a new rental agreement for a house they might have * lost. */ int do_agreement() { string *houses; int i; string place; place = query_property("place"); if (this_player()->query_value_in(place) < NEW_AGREEMENT_COST) { add_failed_mess("You need " + MONEY_HAND-> money_value_string(NEW_AGREEMENT_COST, place) + " to get a new agreement.\n"); return 0; } houses = filter(keys(HOUSING->query_houses()), (: HOUSING->query_owner($1) == $2 :), this_player()->query_name()); if (!sizeof(houses)) { add_failed_mess("You are not renting any houses.\n"); return 0; } for (i = 0; i < sizeof(houses); i++) { printf("%c) %s %s\n", i + 'A', HOUSING->query_address(houses[i]), HOUSING->query_region(houses[i])); } write("It will cost you " + MONEY_HAND-> money_value_string(NEW_AGREEMENT_COST, place) + " for a new " "agreement.\n"); write("Which house to choose? "); input_to("new_agreement_choice", 0, houses); add_succeeded_mess(({ "", "$N enquires about a new rental agreement.\n" })); return 1; } /* do_agreement() */ /** @ignore yes */ protected void new_agreement_choice(string choice, string *houses) { int index; object agreement; string place; place = query_property("place"); choice = lower_case(choice); if (!strlen(choice)) { write("Ok, canceling agreement check.\n"); return; } index = choice[0] - 'a'; if (index < 0 || index >= sizeof(houses)) { write("Choice out of bounds.\n"); return; } if (this_player()->query_value_in(place) < NEW_AGREEMENT_COST) { add_failed_mess("You need " + MONEY_HAND-> money_value_string(NEW_AGREEMENT_COST, place) + " to get a new agreement.\n"); return 0; } this_player()->pay_money(MONEY_HAND-> create_money_array(NEW_AGREEMENT_COST, place)); agreement = clone_object(AGREEMENT); agreement->set_city(_city); agreement->set_language(_language); agreement->set_house(houses[index]); if (agreement->move(this_player()) != MOVE_OK) { write("Unable to move the agreement into your inventory.\n"); return 0; } write("Created a new agreement for " + HOUSING->query_address(houses[index]) + ".\n"); } /* new_agreement_choice() */ /** * This method checks to make sure they have enough money in their bank * accounts to make the bid. This function should be setup to be called * as the big checking function in the inherit of this room. * @param person the person being checked for bidding * @param which the auction being tested to be bid on * @param bid_amount how much they are bidding */ int check_can_bid(object person, class auction which, int bid_amount) { int total_money, total_bids; string *accounts; string account; class auction auction; accounts = "/obj/handlers/bank_handler"->query_accounts(person-> query_name()); foreach(account in accounts) { total_money += "/obj/handlers/bank_handler"->query_account(person-> query_name(), account); } foreach(auction in query_auctions()) { if (auction->current_bidder && lower_case(auction->current_bidder) == person->query_name()) { total_bids += auction->bid; } } if (total_bids + bid_amount > total_money * 3) { add_failed_mess ("You do not have sufficient funds in your bank accounts " "to cover such a bid.\n"); return 0; } return 1; } /* check_can_bid() */ /** @ignore yes */ void init() { ::init(); add_command("request", "[agreement]", (: do_agreement() :)); } /* init() */ /** * This function runs down the list of current auctions and makes sure they * are all registered as "Under Offer" so if for some reason they are not, * they won't be put up for sale again. */ void reset_auctions_to_under_offer() { class auction auc; foreach( auc in query_auctions() ) { HOUSING->set_under_offer(auc->extra); } } /* reset_auctions_to_under_offer() */ /** * This is just a cosmetic function to help set up the agreements. * * @param where the city to which the agreements will say the property * defaults to when you cease to own it */ void set_city( string where ) { _city = where; } /* set_city() */ /** * This is just a cosmetic function to help set up the agreements. * * @param the agreements be written in */ void set_language( string lang ) { _language = lang; } /* set_language() */ /** * Returns the city the real estate place thinks it lives in. */ string query_city() { return _city; } /* query_city() */ /** * Returns the language the real estate place will use for its agreements. */ string query_language() { return _language; } /* query_language() */ mixed *stats() { return ::stats() + ({ ({ "areas", _areas }), ({ "city", _city }), ({ "language", _language }), }); }