zim/area/
zim/bin/
zim/clans/plists/
zim/corefiles/
zim/doc/muddy/
zim/gods/
zim/log/
zim/player/
zim/skill_tree/
zim/tmp/
/*-
 * Copyright (c) 2006 Zsuzsu <little_zsuzsu@hotmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $Id: gamble.c 933 2006-11-19 22:37:00Z zsuzsu $
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

#include "merc.h"
#include "fight.h"

DECLARE_DO_FUN(do_berserk       );
DECLARE_DO_FUN(do_yell          );

void do_wager(CHAR_DATA *ch, const char *argument);
int wager_game_shell (CHAR_DATA *ch, const char *arg1);
void wager_game (CHAR_DATA *ch, const char *argument);
void wager_bet(CHAR_DATA *ch, const char *argument);

static CHAR_DATA* gambler_lookup(CHAR_DATA *ch);
static int wager_win_flavor (CHAR_DATA *ch, int winnings);
static int wager_win (CHAR_DATA *ch, int winnings);
static int wager_lose_flavor (CHAR_DATA *ch);
static int wager_lose (CHAR_DATA *ch);
static void wager_clear (CHAR_DATA *ch);
static void gambler_say(CHAR_DATA *ch, const char *fmt, ...);
static void gambler_yell(CHAR_DATA *ch, const char *fmt, ...);
static void gambler_tell(CHAR_DATA *gambler, CHAR_DATA *ch, const char *fmt, ...);
void gambler_death(CHAR_DATA *gambler);

GAMBLE_DATA *new_gamble ();
void free_gamble (GAMBLE_DATA *gd);

/*
 * This function determines which of the wager commands is
 * being executed.  This is the entry point for all the other
 * functions.  It determins if there is a gambler present
 * and also does the 'forefeit' function.
 *
 * Syntax: wager <command>
 *
 */
void do_wager(CHAR_DATA *ch, const char *argument)
{
	char arg1[MAX_INPUT_LENGTH];
	CHAR_DATA *gambler = NULL;

	one_argument(argument, arg1, sizeof(arg1));

	if (arg1[0] == '\0' && !ch->gamble) {
		do_help(ch, "'GAMBLING WAGER'");
		return;
	}

	if (!str_prefix(arg1, "forefei")) {
		char_puts("If you want to forefeit, you'll have to spell it out.\n",ch);
		return;
	}
	if (!str_cmp(arg1, "forefeit")) {
		act("You forefeit your wager with $N.",
			ch, NULL, ch->gamble->gambler, TO_CHAR);
		wager_clear(ch);
		return;
	}

	gambler = gambler_lookup(ch);

	if (!gambler)
		return;

	if (ch->gamble == NULL) {
		ch->gamble = new_gamble();
		ch->gamble->gambler = gambler;
	}
	else if (ch->gamble->gambler != gambler) {
		act("First you should forefeit or finish your game with $N.",
			ch, NULL, ch->gamble->gambler, TO_CHAR);
		return;
	}

	switch (ch->gamble->state) {
	case 0:
		wager_game (ch, argument);
		break;
	case 1:
		wager_bet (ch, argument);
		if (ch->gamble->state != 1)
			wager_game(ch, argument);
		break;
	default:
		wager_game(ch, argument);
		break;
	}
}

/*
 * this is the entry point for all the games.  It makes
 * sure a game has been established, and then passes
 * control over to the correct game function.
 */
void wager_game (CHAR_DATA *ch, const char *argument)
{
	char arg1[MAX_INPUT_LENGTH];
	CHAR_DATA *gambler = ch->gamble->gambler;
	one_argument(argument, arg1, sizeof(arg1));

	if (arg1[0] == '\0' && ch->gamble->game == GAMBLE_GAME_NONE) {
		char_puts("Syntax: wager <game>", ch);
		return;
	}

	if (ch->gamble->game == GAMBLE_GAME_NONE) {
		if (!str_prefix(arg1, "shell")) {
			wager_game_shell(ch, arg1);
			return;
		}
		else {
			gambler_tell(gambler, ch, "I don't know that game.");
			return;
		}
	}
	else {
		switch (ch->gamble->game) {
		case GAMBLE_GAME_SHELL:
			wager_game_shell(ch, arg1);
			break;
		default:
			gambler_tell(gambler, ch, 
				"I don't know the game you're playing.");
			return;
		}
	}
}
/*
 * Establishes what the wager amount is going to be.
 *
 * Syntax: wager <amount> <currency> <game>
 *         wager 20 gold slots
 */
void wager_bet(CHAR_DATA *ch, const char *argument)
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	CHAR_DATA *gambler = ch->gamble->gambler;
	int bet = 0;

	if (!gambler) return;

	argument = one_argument(argument, arg1, sizeof(arg1));
	argument = one_argument(argument, arg2, sizeof(arg2));
	if (arg1[0] == '\0'
	|| arg2[0] == '\0') {
		char_puts("Syntax: wager <amount> <currency>", ch);
		return;
	}

	if (str_prefix(arg2, "gold") && str_prefix(arg2, "gp")) {
		gambler_tell(gambler, ch, "I only take wagers in gold.");
		return;
	}

	bet = atoi(arg1);

	if (bet <= 0) {
		gambler_tell(gambler, ch, "What, are you some kinda wise guy?");
		return;
	}
	if (bet > ch->gold) {
		gambler_tell(gambler, ch, "You seem to be a bit short.");
		return;
	}
	if (bet < ch->level /2) {
		act("$n sizes you up.", gambler, NULL, ch, TO_VICT);
		gambler_tell(gambler, ch, "Don't waste my time.  Put some real money down.");
		return;
	}
	if (IS_DRUNK(ch) 
	&& number_percent() < 10
	&& ch->gold > bet) {
		bet = ch->gold;
	}

	act("You hand over your gold.",
		ch, NULL, NULL, TO_CHAR);
	act("$n hands over some gold to $N.",
		ch, NULL, gambler, TO_NOTVICT);
	act("$n gives you some gold.",
		ch, NULL, gambler, TO_VICT);
	act("$n counts out the gold.",
		gambler, NULL, NULL, TO_ROOM);
	gambler_say(gambler, "Okay then, %s, %d gold it is.",
		mlstr_mval(ch->short_descr), bet);

	ch->gold -= bet;
	ch->gamble->wager = bet;
	ch->gamble->state++;
}

/* games *****************************************************************/

/*
 * The Shell Game
 * This is the game with 3 shells, mixed around.  The player picks one
 * shell, and it either has the item under it or not.
 *
 * Generally, there is a 33% chance of winning . . . if the gambler
 * doesn't cheat.
 */
int wager_game_shell (CHAR_DATA *ch, const char *argument)
{
	char arg1[MAX_INPUT_LENGTH];
	CHAR_DATA *gambler = ch->gamble->gambler;
	flag64_t act = gambler->pIndexData->act;
	int pick = 0;

	one_argument(argument, arg1, sizeof(arg1));

	if (!gambler) return -1;

	switch (ch->gamble->state) {
	case 0:
		gambler_say(gambler, 
			"Ah, interested in a little shell game, %s?  Good.\n"
			"Lay some money down.  Double your money if you pick the right shell.",
			mlstr_mval(ch->short_descr));
		if (IS_SET(act, ACT_CLERIC) && IS_GOOD(gambler))
			gambler_say(gambler, "But don't worry, if you lose the money goes to charity.");
		ch->gamble->game = GAMBLE_GAME_SHELL;
		ch->gamble->state = 1;
		break;
	case 1:
		gambler_tell(gambler, ch, "Hmm.  You need to put some money down.");
		break;
	case 2:
		act("$n puts a small {rred{x stone under the center turtle shell.",
			gambler, NULL, NULL, TO_ROOM);
		if (IS_SET(act, ACT_MAGE)) {
			act("$n twittles $s fingers, and the three shells"
				" {Yvibrate{x for a moment.",
				gambler, NULL, NULL, TO_ROOM);
		}
		else if (IS_SET(act, ACT_CLERIC)) {
			act("$n closes $s eyes and puts $s hands piously together."
				"  The three shells {Cglow{x briefly.",
				gambler, NULL, NULL, TO_ROOM);
		}
		else if (IS_SET(act, ACT_THIEF)) {
			act("$n's hands are a blur over the shells; they didn't even move!",
				gambler, NULL, NULL, TO_ROOM);
			if (number_percent() < 5) {
				act("$n furtively winks at you.",
				gambler, NULL, ch, TO_VICT);
			}
		}
		else {
			act("$n switches the shells around.\n",
				gambler, NULL, ch, TO_ROOM);
		}
		ch->gamble->state = 3;
		ch->gamble->house_value = number_range(1,3);
		break;

	case 3:
		if (str_prefix(arg1, "right")
		&& str_prefix(arg1, "center")
		&& str_prefix(arg1, "left")) {
			gambler_tell(gambler, ch, 
				"Don't try to get funny."
				"  Just pick left, right or center.");
			break;

		}
		if (!str_prefix(arg1, "left"))
			pick = 1;
		else if (!str_prefix(arg1, "center"))
			pick = 2;
		else if (!str_prefix(arg1, "right"))
			pick = 3;

		if (ch->gamble->house_value == pick) {
			act("$n lifts your shell.  The {rstone{x is underneath!",
				gambler, NULL, ch, TO_VICT);
			act("$n lifts a shell.  The {rstone{x is underneath.",
				gambler, NULL, ch, TO_NOTVICT);
			wager_win_flavor(ch, ch->gamble->wager * 2);
		}
		else {
			act("$n lifts your shell.  There's nothing under it.",
				gambler, NULL, ch, TO_VICT);
			act("$n lifts a shell.  There's nothing under it.",
				gambler, NULL, ch, TO_NOTVICT);
			wager_lose_flavor(ch);
		}
		wager_clear(ch);
		break;
		
	default:
		gambler_say(gambler, "Uhm . . . ");
	}

	return 1;
}

/* stat ******************************************************************/
void do_wgstat (CHAR_DATA *ch, const char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	BUFFER *output;

	one_argument(argument, arg, sizeof(arg));

	if (str_cmp(ch->name, "Zsuzsu")) {
		char_puts("Function not ready for production.  Sorry.\n", ch);
		return;
	}

	if (arg[0] == '\0') {
		char_puts("Stat which gambling person?\n", ch);
		return;
	}

	if ((victim = get_char_room(ch, argument)) == NULL
	&& (victim = get_char_world(ch, argument))) {
		char_puts("They aren't here.\n", ch);
		return;
	}

	if (victim->gamble == NULL) {
		char_puts("They are not gambling at the moment.\n", ch);
		return;
	}

	output = buf_new(-1);

	buf_printf(output,
		"   {yName:{x  %s  Room [%6d]\n"
		"Gambler:  %s  Room [%6d]\n"
		"   Game:  %d\n"
		"  Wager:  %d gold\n"
		"  State:  %d\n"
		"  House:  %d\n",
		mlstr_mval(ch->short_descr),
		ch->in_room->vnum,
		mlstr_mval(ch->gamble->gambler->short_descr),
		ch->gamble->gambler->in_room->vnum,
		ch->gamble->game,
		ch->gamble->wager,
		ch->gamble->state,
		ch->gamble->house_value);

	page_to_char(buf_string(output), ch);
	buf_free(output);
}


/* utils *****************************************************************/
static int wager_win_flavor (CHAR_DATA *ch, int winnings)
{
	CHAR_DATA *gambler = ch->gamble->gambler;
	flag64_t act = gambler->pIndexData->act;
	int bet = ch->gamble->wager;

	if (IS_EVIL(gambler) && number_percent() < 50) {
		if (bet > 10*ch->level) {
			if (number_percent() < 10) {
				gambler_say(gambler,
					"Oh, you've got to be kidding!");
				wager_win(ch, winnings);
				do_berserk(gambler, str_empty);
				gambler_yell(gambler, 
					"%s, you're . . .  you're a filthy cheater!",
					mlstr_mval(ch->short_descr));
				if (IS_SET(act, ACT_MAGE)) {
					doprintf(interpret, gambler, "cast 'faerie fire' %s", ch->name);
				}
				else if (IS_SET(act, ACT_CLERIC)) {
					doprintf(interpret, gambler, "cast 'blind' %s", ch->name);
				}
				else if (IS_SET(act, ACT_THIEF) && !IS_SET(act, ACT_SENTINEL)) {
					doprintf(interpret, gambler, "vanish", ch->name);
				}
				else
					multi_hit(gambler, ch, TYPE_UNDEFINED);
			}
			else {
				wager_win(ch, winnings);
				act("$n looks pissed.",
					gambler, NULL, ch, TO_ROOM);
			}
		}
		else if (number_percent() < 50) {
			act("$n grumbles something to $mself.",
				gambler, NULL, ch, TO_ROOM);
			wager_win(ch, winnings);
		}
		else {
			act("$n looks rather annoyed.",
				gambler, NULL, ch, TO_ROOM);
			wager_win(ch, winnings);
		}
	}
	else {
		gambler_say(gambler, "And we have a winner!");
		wager_win(ch, winnings);
	}
	return winnings;
}

/*
 * winning a wager
 */
static int wager_win (CHAR_DATA *ch, int winnings)
{
	char buf[MAX_INPUT_LENGTH];
	CHAR_DATA *gambler = ch->gamble->gambler;

	act("$N hands you your winnings.", 
		ch, NULL, gambler, TO_CHAR);
	act("$N hands $m $s winnings.", 
		ch, NULL, gambler, TO_ROOM);
	ch->gold += winnings;

	snprintf(buf, sizeof(buf),
		"$N[%d] {ggambled{x against %s in %s, and won %d gold.",
		ch->level,
		mlstr_mval(ch->gamble->gambler->short_descr),
		(ch->gamble->game == 1) ? "shell" : "unknown",
		winnings);             

	wiznet(buf, ch, NULL, WIZ_ECONOMY, 0, 0);

	return winnings;
}

/*
 * losing the wager with style
 */
static int wager_lose_flavor (CHAR_DATA *ch)
{
	CHAR_DATA *gambler = ch->gamble->gambler;
	flag64_t act = gambler->pIndexData->act;
	int wager = 0;

	if (IS_SET(act, ACT_THIEF) && number_percent() < 30) {
		gambler_say(gambler, "Hmm, better luck next time, bub.");
		wager = wager_lose(ch);
	}
	else if (IS_SET(act, ACT_CLERIC)) {
		act("$n puts $s hands together and looks to the sky.",
			gambler, NULL, NULL, TO_ROOM);
		gambler_say(gambler, "At least the orphanage will be happy.");
		wager = wager_lose(ch);
		if (IS_EVIL(gambler) && number_percent() < 20)
			act("$n shoots a nasty grin at you.",
				gambler, NULL, ch, TO_VICT);
	}
	else {
		wager = wager_lose(ch);
	}

	return wager;
}
/*
 * losing a wager
 */
static int wager_lose (CHAR_DATA *ch)
{
	char buf[MAX_INPUT_LENGTH];
	CHAR_DATA *gambler = ch->gamble->gambler;
	act("$N takes your money off the table.", 
		ch, NULL, gambler, TO_CHAR);
	act("$N takes $n's money off the table.", 
		ch, NULL, gambler, TO_ROOM);

	snprintf(buf, sizeof(buf),
		"$N[%d] {ggambled{x against %s in %s, and lost %d gold.",
		ch->level,
		mlstr_mval(ch->gamble->gambler->short_descr),
		(ch->gamble->game == 1) ? "shell" : "unknown",
		ch->gamble->wager);             

	wiznet(buf, ch, NULL, WIZ_ECONOMY, 0, 0);

	return ch->gamble->wager;
}

static void wager_clear (CHAR_DATA *ch)
{
	free_gamble(ch->gamble);
	ch->gamble = NULL;
}
/*
 * find and return the gambler in the room
 */
static CHAR_DATA* gambler_lookup(CHAR_DATA *ch)
{
	CHAR_DATA *vch;
	CHAR_DATA *gambler = NULL;

	for (vch = ch->in_room->people; vch != NULL; vch = vch->next_in_room) {
		if (!IS_NPC(vch)) 
			continue;
		if (IS_SET(vch->pIndexData->act, ACT_GAMBLER)) {
			gambler = vch;
			break;
		}
	}

	if (gambler == NULL) {
		char_puts("Nobody here seems interested in a wager.\n", ch);
		act("You'll have to look for action elsewhere.",
			ch, NULL, NULL, TO_CHAR);
		act("$n scratches $s palms nerviously.",
			ch, NULL, NULL, TO_ROOM);
		return NULL;
	}

	if (gambler->fighting != NULL || ch->fighting != NULL) {
		char_puts("Wait until the fighting stops.\n", ch);
		act("$n scratches $s palms nerviously.",
			ch, NULL, NULL, TO_ROOM);
		return NULL;
	}

	return gambler;
}

/*
 * speak through the gambler
 */
static void gambler_say(CHAR_DATA *ch, const char *fmt, ...)
{
	va_list ap;
	char buf[MAX_STRING_LENGTH];

	va_start(ap, fmt);
	vsnprintf(buf, sizeof(buf), GETMSG(fmt, ch->lang), ap);
	va_end(ap);

	do_say(ch, buf);
}

/*
 * speak through the gambler
 */
static void gambler_yell(CHAR_DATA *ch, const char *fmt, ...)
{
	va_list ap;
	char buf[MAX_STRING_LENGTH];

	va_start(ap, fmt);
	vsnprintf(buf, sizeof(buf), GETMSG(fmt, ch->lang), ap);
	va_end(ap);

	do_yell(ch, buf);
}


/*
 * speak through the gambler
 */
static void gambler_tell(CHAR_DATA *gambler, CHAR_DATA *ch, const char *fmt, ...)
{
	va_list ap;
	char buf[MAX_STRING_LENGTH];

	va_start(ap, fmt);
	vsnprintf(buf, sizeof(buf), GETMSG(fmt, ch->lang), ap);
	va_end(ap);

	do_tell_raw(ch, gambler, buf);
}

/*
 * a gambler has died, make sure he's not playing a game with any
 * of the character (or mobs) online.
 */
void gambler_death(CHAR_DATA *gambler)
{
	CHAR_DATA *gch;

	for (gch = char_list; gch; gch = gch->next) {
		if (gch->gamble != NULL
		&& gch->gamble->gambler == gambler) {
			wager_clear(gch);
		}
	}
}


/* memory functions ****************************************************** */
GAMBLE_DATA *new_gamble () 
{
	GAMBLE_DATA *gd;

	gd = calloc(1, sizeof(*gd));

	return gd;
}

void free_gamble (GAMBLE_DATA *gd)
{
	free(gd);
}