dawn/notes/
dawn/src/
dawn/src/docs/
/**************************************************************************/
// shop.cpp - shop functionality written by Slortar
/***************************************************************************
 * The Dawn of Time v1.69r (c)1997-2004 Michael Garratt                    *
 * >> A number of people have contributed to the Dawn codebase, with the   *
 *    majority of code written by Michael Garratt - www.dawnoftime.org     *
 * >> To use this source code, you must fully comply with the dawn license *
 *    in licenses.txt... In particular, you may not remove this copyright  *
 *    notice.                                                              *
 ***************************************************************************/

#include "shop.h"

/**************************************************************************/
/*
 * The default constructor. Don't forget to initliase new member variables
 * here.
 * \return Nothing.
 * \param None.
 */
cShopData::cShopData()
{
	close_hour		= 23;
	open_hour		= 0;
	profit_buy		= 100;
	profit_sell		= 100;
	vnKeeper		= 0;
}

/**************************************************************************/
/*
 * The default destructor.
 * \return Nothing.
 * \param None.
 */
cShopData::~cShopData()
{

}

/**************************************************************************/
/*
 * The default constructor. Don't forget to initliase new member variables
 * here.
 * \return Nothing.
 * \param None.
 */
cInnData::cInnData()
{
	pNextInn		= NULL;
	for(int i=0; i<MAX_INN; i++){
		vnRoom[i]=0;
		shRate[i]=0;
	}
}

/**************************************************************************/
/*
 * The default destructor.
 * \return Nothing.
 * \param None.
 */
cInnData::~cInnData()
{

}

/**************************************************************************/
/* Returns the first NPC in the same room as *ch that is an innkeeper. If there
 * is an innkeeper in the room, but he's unavailable for action. Closing hours,
 * unable to see *ch, then NULL is returned.
 * \return The pointer to the char_data structure of a NPC innkeeper.
 * \param ch Pointer to the char_data structure of a player.
 */
char_data* find_innkeeper(char_data *ch)
{
	cInnData* pInn		= NULL;
	char_data* pKeeper	= NULL;
	
	for ( pKeeper=ch->in_room->people; pKeeper; pKeeper=pKeeper->next_in_room ) {
		if ( IS_NPC(pKeeper) && (pInn=pKeeper->pIndexData->pInnData) != NULL ) {
			break;
		}
	}

	// No innkeeper in the room.
	if ( pInn == NULL ) {
		ch->println("You can't do that here.");
		return NULL;
    }

    // Shop hours.
    if ( time_info.hour < pInn->open_hour )
    {
		do_say( pKeeper, "Sorry, I am closed. Come back later." );
		return NULL;
    }
	if ( time_info.hour > pInn->close_hour )
    {
		do_say( pKeeper, "Sorry, I am closed. Come back tomorrow." );
		return NULL;
    }

    // Invisible or hidden people.
	if ( !can_see( pKeeper, ch )  && INVIS_LEVEL(ch)<1)
    {
		do_say( pKeeper, "I don't rent to folks I can't see." );
		return NULL;
	}
	
    return pKeeper;
}

/**************************************************************************/
/*
 * Allows players to rent a room. The function makes the necesary checks on 
 * the room and the player etc. Then the function parses the argument which
 * should represent the number of hours the player wishes to rent the room.
 * Renting a room will set the player's first point of recall to this room,
 * for a certain amount of hours.
 * \return Nothing.
 * \param ch The pointer to the player's char_data structure.
 * \param aArg The string containing the input the player supplied.
 */
void do_rent( char_data *ch, char *aArg)
{
	char_data* pInnKeeper			= NULL;
	cInnData* pInn					= NULL;
	ROOM_INDEX_DATA* pRoom			= NULL;
	const double uiTicksPerGameHour	= 11.4;
	unsigned int uiNumHours			= 0;
	vn_int roomVnum					= 0;
	long roomRate					= 0;
	int roomCost					= 0;
	int roomHaggle					= 0;
	sh_int roomIdx					= 0;
	char arg1[MIL];				
	char arg2[MIL];

	aArg = one_argument(aArg, arg1);
	aArg = one_argument(aArg, arg2);

	// Check the room is an inn.
	if ( (ch->in_room != NULL) && (!IS_SET(ch->in_room->room_flags, ROOM_INN)) ) {
		ch->println("Perhaps try renting a room at an inn.");
		if(IS_IMMORTAL(ch) || HAS_SECURITY(ch,1)){
			ch->wrapln("[imm/builder only message] A room must have the INN flag set.");
		}
		return;
	}

	// Find the innkeeper.
	if ( (pInnKeeper=find_innkeeper(ch)) == NULL ) {
		ch->println("The innkeeper seems to have run off.");
		if(IS_IMMORTAL(ch) || HAS_SECURITY(ch,1)){
			ch->wrapln("[imm/builder only message] This room is marked as an inn, but a mob with an inn assigned "
				"was not found (or outside the hours for their inn).");
		}
		return;
	}

	// Check arguments.
	if ( !is_number(arg1) || !is_number(arg2) ) {
		ch->println("Syntax: rent <room number> <number of hours>");
		return;
	}

	roomIdx			= (sh_int)atoi(arg1);
	if(roomIdx<1 || roomIdx>MAX_INN){
		ch->println("Syntax: rent <room number> <number of hours>");
		ch->printlnf("The room number must be between 1 and %d", MAX_INN);		
		return;
	}

	uiNumHours		= (sh_int)atoi(arg2);
	pInn			= pInnKeeper->pIndexData->pInnData;

	// Get the relevant room details.
	roomVnum = pInn->vnRoom[roomIdx-1]; 
	roomRate = pInn->shRate[roomIdx-1]; 

	// Check the room is a valid room.
	if ( (pRoom=get_room_index(roomVnum))==NULL ) {
		ch->println("That room is not available.");
		return;
	}

	// Calculate the cost and check the cost will be positive.
	if ( (roomCost=(roomRate*uiNumHours)) <= 0 ) {
		ch->println("You can't rent a room for that amount of hours.");
		return;
	}

	// haggle ( code taken from do_buy the petshop bit, made a few alterations. )
	roomHaggle = number_percent();
	if (roomHaggle < get_skill(ch,gsn_haggle)) {
		// Haggle succeeded.

		roomCost -= roomCost / 2 * roomHaggle / 100;
		if ( (ch->silver + 100 * ch->gold) < roomCost)
		{				
			ch->printlnf( "You haggle the price down to %d coin%s, but "
				"still can't afford it.", roomCost, roomCost==1?"":"s");
			
			if ( (ch->silver + 100 * ch->gold) > (roomCost * 96/100) )
			{				
				roomCost=(ch->silver + 100 * ch->gold);
				ch->printlnf( "You explain this to the innkeeper and manage to "
					"haggle the price down to the money that you do have!");
			} else { // didn't get it
				WAIT_STATE(ch, 20); // 5 seconds lag to reduce potential abuse
				return;
			}
		} else {
			ch->printlnf( "You haggle the price down to %d coin%s.",
				roomCost, roomCost==1?"":"s");
			check_improve(ch, gsn_haggle, true, 4);
		}		
	}else{
		// Haggle failed.
		if ( (ch->silver + 100 * ch->gold) < roomCost ) {
			ch->println("You can't afford it.");
			check_improve(ch, gsn_haggle, false, 2);

			return;
		} else {
			ch->printlnf( "You succesfully rented a room for %d coin%s.",
				roomCost, roomCost==1?"":"s");
		}
	}

	deduct_cost(ch, roomCost);

	// If you're renting the same room, then just add the extra days to the end of your 
	// current period. Rounded downwards.
	if ( ch->recall_inn_room == roomVnum && ch->expire_recall_inn>0 ) {
		uiNumHours+=(ch->expire_recall_inn / (int)uiTicksPerGameHour);
	} else {
		ch->recall_inn_room = roomVnum;
	}
	
	ch->expire_recall_inn=(int)(uiNumHours*uiTicksPerGameHour);

	ch->printlnf("You will recall to `#%s`^ for the following %d hour%s.", pRoom->name, uiNumHours, uiNumHours==1 ? "" : "s");
	ch->println("Type `#`=Crecall reset`^ to cancel this and recall to your default location.");

    return;
}


/**************************************************************************/
/**************************************************************************/