dotd-2.3.7/area/
dotd-2.3.7/clans/
dotd-2.3.7/classes/
dotd-2.3.7/councils/
dotd-2.3.7/deity/
dotd-2.3.7/dict/
dotd-2.3.7/doc/mudprogs/
dotd-2.3.7/player/a/
dotd-2.3.7/player/g/
/******************************************************
            Desolation of the Dragon MUD II
      (C) 1997-2002  Jesse DeFer and Heath Leach
          http://www.dotd.com  dotd@dotd.com
 ******************************************************/

/*static char rcsid[] = "$Id: ospecial.c,v 1.35 2004/04/06 22:00:10 dotd Exp $";*/

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "mud.h"
#include "currency.h"
#include "gsn.h"

DECLARE_DO_FUN(do_pull);
DECLARE_DO_FUN(do_drop);
DECLARE_DO_FUN(do_kill);
DECLARE_DO_FUN(do_wear);
DECLARE_DO_FUN(do_say);
DECLARE_DO_FUN(do_use);

#define SPEC SPECIAL_FUNC
#include "ospecial.h"
#undef SPEC

#define SPEC(func) \
    if (++i==2) {i=0;send_to_pager("\n\r",ch);} pager_printf(ch, "%-38s", #func)
void do_oslist( CHAR_DATA *ch, char *argument )
{
    int i=-1;

    set_pager_color(AT_PLAIN,ch);

    #include "ospecial.h"

    send_to_pager( "\n\r", ch );
}
#undef SPEC

#define SPEC(func) \
    if (obj->spec_fun == func && strstr(#func, argument)) \
    { ch_printf(ch, "u%-5d %5d: %s\n\r", obj->unum, obj->vnum, #func); match++; continue; }
void do_osfind( CHAR_DATA *ch, char *argument )
{
    OBJ_DATA *obj;
    int match=0;

    if (!argument)
    {
        send_to_char("osfind <name>\n\r", ch);
        return;
    }
    for (obj=first_object;obj;obj=obj->next)
    {
        if (!obj->spec_fun)
            continue;
#include "ospecial.h"
    }
    ch_printf(ch, "%d matches found.\n\r", match);
}
#undef SPEC

/*
 * Given a name, return the appropriate spec fun.
 */
#define SPEC(func) \
    if ( !str_cmp( name, #func ) ) return func
SPEC_FUN *o_spec_lookup( const char *name )
{
    #include "ospecial.h"
    return NULL;
}
#undef SPEC

/*
 * Given a pointer, return the appropriate spec fun text.
 */
#define SPEC(func) \
    if ( special == func ) return #func
char *o_lookup_spec( SPEC_FUN *special )
{
    #include "ospecial.h"
    return "";
}
#undef SPEC


SPECIAL_FUNC(spec_nodrop)
{
    if (type!=SFT_COMMAND || cmd->do_fun!=do_drop)
	return FALSE;

    if (IS_IMMORTAL(cmd_ch))
	send_to_char("It resists your attept to drop it, but you do anyway.\n\r", cmd_ch);
    else
	send_to_char("You cannot drop that.\n\r", cmd_ch);
    return TRUE;
}

char * const slot_values[6] =
{
    "&YLemon  ", "&OOrange ", "&RCherry ",
    "&GLime   ", "&WBar    ", "&YGold   "
};
SPECIAL_FUNC(spec_SlotMachine)
{
    OBJ_DATA *obj = (OBJ_DATA *)proc;
    char buf[MAX_INPUT_LENGTH];
    int c, i[3], ind=0, last;

    if (type==SFT_UPDATE && obj)
    {
        send_to_room("A slot machine twinkles with luring magics.\n\r",obj->in_room);
        return(TRUE);
    }

    if (type!=SFT_COMMAND || cmd->do_fun!=do_pull)
        return(FALSE);

    if (str_prefix(arg, "handle")) {
        send_to_char("You grope for something and pull it... Someone doesn't look too happy.\n\r", cmd_ch);
        return(TRUE);
    }

    if (GET_MONEY(cmd_ch,CURR_GOLD) < obj->value[4])
    {
        send_to_char("You don't have enough gold!\n\r", cmd_ch);
        return(TRUE);
    }
    else
    {
        send_to_char("You pull the handle and await the results...\n\r", cmd_ch);
    }

    WAIT_STATE(cmd_ch, PULSE_PER_SECOND);

    if (obj->value[5] <= obj->value[4])
        obj->value[5] = obj->value[4]*10;

    GET_MONEY(cmd_ch,CURR_GOLD) -= obj->value[4];
    obj->value[5] += obj->value[4];

    last = 0;
    for (c = 0; c < 3; c++)
    {
        int x = number_range(0, 40) + URANGE(-4, get_curr_lck(cmd_ch) - 16, 4);
        if (x < 8)
            i[c] = 0;
        else if (x < 8+7)
            i[c] = 1;
        else if (x < 8+7+6)
            i[c] = 2;
        else if (x < 8+7+6+5)
            i[c] = 3;
        else if (x < 8+7+6+5+4)
            i[c] = 4;
        else if (x < 8+7+6+5+4+3)
            i[c] = 5;
        else
            i[c] = last;
        send_to_char(slot_values[i[c]], cmd_ch);
        last = i[c];
    }
    send_to_char("&w\n\r", cmd_ch);

    /* if all three are same or cherry same same */
    if ((i[0] == i[1] || i[0] == 2) && i[1] == i[2])
    {
        act(AT_MAGIC,"$n wins some money from the slot machine!",cmd_ch,NULL,NULL,TO_ROOM);

        switch(i[0])
        {
        case 0:
            ind = obj->value[4]; /* Give them back what they put in */
            break;
        case 1:
            ind = obj->value[4]*5;
            break;
        case 2:
            ind = obj->value[4]*10;
            break;
        case 3:
            ind = obj->value[4]*20;
            break;
        case 4:
            ind = obj->value[4]*40;
            break;
        case 5:
            ind = obj->value[5]; /* Wow! We've won big! */
            if (i[0] == i[1])
                send_to_area("Magical telltales start popping off and twinkling lights flash everywhere!\n\r",cmd_ch->in_room->area);
            break;
        }
        if (i[0] == 2 && i[0] != i[1])
            ind /= 2;

        if (ind > obj->value[5])
            ind = obj->value[5]; /* Can only win as much as there is */

        sprintf(buf, "You won %d coins!\n\r", ind);
        send_to_char(buf, cmd_ch);

        GET_MONEY(cmd_ch,CURR_GOLD) += ind;
        obj->value[5] -= ind;
        return(TRUE);
    }

    send_to_char("Sorry, you lost.\n\r", cmd_ch);
    return(TRUE);
}

void do_bet(CHAR_DATA *ch, char *argument)
{
    send_to_char("You can't do that here.\n\r", ch);
}

#define ROULETTE_HOUSE_LIMIT   50000
#define ROULETTE_PLACES        31
#define ROULETTE_PLACE_RED     ROULETTE_PLACES+1
#define ROULETTE_PLACE_BLACK   ROULETTE_PLACES+2
SPECIAL_FUNC(spec_RouletteWheel)
{
    char arg2[MAX_INPUT_LENGTH];
    int currtype = CURR_GOLD;
    int bet=0,placement=0,roll=0;

    if (type!=SFT_COMMAND || cmd->do_fun!=do_bet)
        return(FALSE);

    arg = one_argument(arg, arg2);

    if (arg2[0] == '\0' || !arg || !*arg)
    {
        send_to_char("To play roulette, bet <coins> <0-31|red|black>\n\r", cmd_ch);
        return(TRUE);
    }

    bet = atoi(arg2);
    if (bet <= 0)
    {
        send_to_char("You must bet a positive amount.\n\r", cmd_ch);
        return(TRUE);
    }

    if (bet > ROULETTE_HOUSE_LIMIT && !IS_IMMORTAL(cmd_ch))
    {
        ch_printf(cmd_ch, "I'm sorry, but house rules say you can't bet more than %d coins.\n\r",
                  ROULETTE_HOUSE_LIMIT);
        return(TRUE);
    }
    if (GET_MONEY(cmd_ch, currtype) < bet)
    {
        ch_printf(cmd_ch, "You do not have that much %s.\n\r", curr_types[currtype]);
        return(TRUE);
    }

    if (!str_cmp(arg, "red"))
        placement = ROULETTE_PLACE_RED;
    else if (!str_cmp(arg, "black"))
        placement = ROULETTE_PLACE_BLACK;
    else
    {
        placement = atoi(arg);
        if (placement < 0 || placement > ROULETTE_PLACES)
        {
            send_to_char("Please pick red, black, or a number from 0 to 31.\n\r", cmd_ch);
            return(TRUE);
        }
    }

    GET_MONEY(cmd_ch, currtype) -= bet;
    roll = number_range(0, ROULETTE_PLACES);
    send_to_char("The dealer spins the wheel...\n\r", cmd_ch);
    send_to_char("The dealer drops the ball...\n\r", cmd_ch);

    if (roll==0)
        send_to_char("&WThe ball lands on &G00&W!\n\r", cmd_ch);
    else
        ch_printf(cmd_ch, "&WThe ball lands on %s %d&W!\n\r",
                  roll%2?"&zblack":"&rred", roll);

    if (placement==roll)
    {
        bet*=32;
        ch_printf(cmd_ch, "You picked %d, you win %d coins!!!\n\r", placement, bet);
    }
    else if (roll%2==0 && roll!=0 && placement==ROULETTE_PLACE_RED)
    {
        bet*=2;
        ch_printf(cmd_ch, "You bet on red, you win %d coins!!!\n\r", bet);
    }
    else if (roll%2!=0 && placement==ROULETTE_PLACE_BLACK)
    {
        bet*=2;
        ch_printf(cmd_ch, "You bet on black, you win %d coins!!!\n\r", bet);
    }
    else
    {
        send_to_char("You lost!\n\r", cmd_ch);
        bet=0;
    }

    if (bet>1000)
    {
        char buf[MAX_INPUT_LENGTH];
        sprintf(buf, "$n wins %d coins on the roulette wheel.", bet);
        act(AT_WHITE, buf, cmd_ch, NULL, NULL, TO_ROOM);
    }

    GET_MONEY(cmd_ch, currtype) += bet;

    set_char_color(AT_PLAIN, cmd_ch);
    return(TRUE);
}


const char *card_nums[13] =
{
    "ace", "two", "three", "four", "five", "six", "seven", "eight",
    "nine", "ten", "jack", "queen", "king"
};
const char *card_suites[4] =
{
    "hearts", "spades", "diamonds", "clubs"
};

static char *cardname(int card)
{
    static char retbuf[32];

    snprintf(retbuf, 32, "%s%s of %s&w",
             (card%2)==0?"&R":"&z",
             card_nums[(card%13)],
             card_suites[(card%4)]);

    return retbuf;
}

static int handtotal(char *hand)
{
    int x, y, tot=0, aces=0;

    for (x=0;x<strlen(hand);x++)
    {
        y = hand[x]-'a'+1;
        if (y<1 || y>13)
        {
            bug("spec_VideoBlackJack: hand has invalid card: %d", y);
            y = 10;
        }
        if (y == 1)
            aces++;
        else if (y > 10)
            tot += 10;
        else
            tot += y;
    }

    while (aces-- > 0)
    {
        if (tot <= 10)
            tot += 11;
        else
            tot += 1;
    }

    return tot;
}

#define BLACKJACK_CARDS 52
SPECIAL_FUNC(spec_VideoBlackJack)
{
    OBJ_DATA *obj = (OBJ_DATA *)proc;
    VAR_DATA *var;
    int x, currtype = CURR_GOLD, bet = 0;
    char deck[BLACKJACK_CARDS+1];
    char phand[BLACKJACK_CARDS], dhand[BLACKJACK_CARDS];
    char tbuf[2];

    if (type==SFT_UPDATE && obj && number_percent()<10)
    {
        send_to_room("A blackjack dealer looks at you expectantly.\n\r", obj->in_room);
        return TRUE;
    }

    if (type!=SFT_COMMAND)
        return FALSE;

    if (cmd->do_fun == do_bet)
    {
        char arg2[MAX_INPUT_LENGTH];
        int y;

        if (get_var(cmd_ch->vars, "VBJdeck"))
        {
            send_to_char("You are already playing a game, you cannot bet any more.\n\r", cmd_ch);
            return TRUE;
        }

        arg = one_argument(arg, arg2);
        if (!is_number(arg2))
        {
            send_to_char("Bet how much?\n\r", cmd_ch);
            return TRUE;
        }
        bet = atoi(arg2);

        if (arg && *arg)
            currtype = get_currency_type(arg);

        if (currtype == CURR_NONE || bet <= 0)
        {
            send_to_char("Bet how much?\n\r", cmd_ch);
            return TRUE;
        }

        if (GET_MONEY(cmd_ch, currtype) < bet)
        {
            ch_printf(cmd_ch, "You don't have that much %s.\n\r",
                      curr_types[currtype]);
            return TRUE;
        }

        cmd_ch->money[currtype] -= bet;

        set_var_int(&cmd_ch->vars, "VBJbet", bet);
        set_var_int(&cmd_ch->vars, "VBJcurr", currtype);

        for (x=0;x<BLACKJACK_CARDS;x++)
            deck[x]='c';
        deck[BLACKJACK_CARDS]='\0';

        if (bet > 5000)
        {
            char buf[32];
            sprintf(buf, "%d %s", bet, curr_types[currtype]);
            act(AT_PLAIN, "$n bets $t on a game of blackjack!", cmd_ch, buf, NULL, TO_ROOM);
        }

        send_to_char("You start a new game, and the dealer suffles the deck.\n\r", cmd_ch);

        phand[0]='\0';
        x = number_range(0,BLACKJACK_CARDS-1);
        sprintf(tbuf, "%c", 'a'+(x%13));
        strcat(phand, tbuf);
        deck[x] = '-';

        dhand[0]='\0';
        while ((y = number_range(0,BLACKJACK_CARDS-1)) == x) ;
        sprintf(tbuf, "%c", 'a'+(y%13));
        strcat(dhand, tbuf);
        deck[y] = '-';

        ch_printf(cmd_ch, "You are dealt a %s.\n\r", cardname(x));
        if (IS_IMMORTAL(cmd_ch))
            ch_printf(cmd_ch, "Dealer gets a %s.\n\r", cardname(y));

        set_var(&cmd_ch->vars, "VBJdeck", deck);
        set_var(&cmd_ch->vars, "VBJphand", phand);
        set_var(&cmd_ch->vars, "VBJdhand", dhand);
        return TRUE;
    }

    if (cmd->do_fun != do_kill &&
        cmd->do_fun != do_wear)
        return FALSE;

    if (!(var = get_var(cmd_ch->vars, "VBJdeck")))
        return FALSE;

    strncpy(deck, get_var_val_ch(cmd_ch, "VBJdeck"), BLACKJACK_CARDS+1);
    strncpy(phand, get_var_val_ch(cmd_ch, "VBJphand"), BLACKJACK_CARDS);
    strncpy(dhand, get_var_val_ch(cmd_ch, "VBJdhand"), BLACKJACK_CARDS);

    if (cmd->do_fun == do_kill)
    {
        int c = 0;
        x = number_range(0,BLACKJACK_CARDS-1);
        while (deck[x] == '-' && c < 50)
        {
            x = number_range(0,BLACKJACK_CARDS-1);
            c++;
        }

        if (deck[x] == '-')
        {
            bug("spec_VideoBlackJack: couldn't get a card!?!?");
            send_to_char("This machine is broken, please try another...\n\r", cmd_ch);
            return TRUE;
        }

        sprintf(tbuf, "%c", 'a'+(x%13));
        strcat(phand, tbuf);
        deck[x] = '-';

        ch_printf(cmd_ch, "You get a %s, your hand total is %d.\n\r",
                  cardname(x), handtotal(phand));

        if (handtotal(phand) > 21)
        {
            send_to_char("You bust.\n\r", cmd_ch);
            del_var(cmd_ch->vars, "VBJdeck");
            del_var(cmd_ch->vars, "VBJhand");
            del_var(cmd_ch->vars, "VBJcurr");
            del_var(cmd_ch->vars, "VBJbet");
            return TRUE;
        }
    }

    /* dealer takes a card/cards */
    while (handtotal(dhand) < 17)
    {
        int c = 0;
        x = number_range(0,BLACKJACK_CARDS-1);
        while (deck[x] == '-' && c < 50)
        {
            x = number_range(0,BLACKJACK_CARDS-1);
            c++;
        }

        if (deck[x] == '-')
        {
            bug("spec_VideoBlackJack: couldn't get a card!?!?");
            send_to_char("This machine is broken, please try another...\n\r", cmd_ch);
            return TRUE;
        }

        sprintf(tbuf, "%c", 'a'+(x%13));
        strcat(dhand, tbuf);
        deck[x] = '-';

        if (!IS_IMMORTAL(cmd_ch))
            ch_printf(cmd_ch, "Dealer gets a %s.\n\r",
                      cardname(x));
        else
            ch_printf(cmd_ch, "Dealer gets a %s, dealer has %d.\n\r",
                      cardname(x), handtotal(dhand));

        if (cmd->do_fun == do_kill)
            break;
    }

    if (cmd->do_fun == do_wear || handtotal(phand) > 21)
    {
        bet = UMAX(0, get_var_val_int_ch(cmd_ch, "VBJbet"));
        currtype = URANGE(CURR_GOLD, get_var_val_int_ch(cmd_ch, "VBJcurr"), MAX_CURR_TYPE-1);
        if (handtotal(dhand) > 21)
        {
            send_to_char("Dealer busts.\n\r", cmd_ch);
            bet *= 2;
        }
        else if (handtotal(phand) > handtotal(dhand))
        {
            send_to_char("You win.\n\r", cmd_ch);
            bet *= 2;
        }
        else if (handtotal(dhand) > handtotal(phand))
        {
            send_to_char("Dealer wins.\n\r", cmd_ch);
            bet = 0;
        }
        else
        {
            send_to_char("Tied.\n\r", cmd_ch);
        }

        if (bet)
        {
            if (bet > 5000)
            {
                char buf[32];
                sprintf(buf, "%d %s", bet, curr_types[currtype]);
                act(AT_PLAIN, "$n wins $t on a game of blackjack!", cmd_ch, buf, NULL, TO_ROOM);
            }
            ch_printf(cmd_ch, "You win %d %s coins!\n\r",
                      bet, curr_types[currtype]);

            GET_MONEY(cmd_ch, currtype) += bet;
        }

        del_var(cmd_ch->vars, "VBJdeck");
        del_var(cmd_ch->vars, "VBJphand");
        del_var(cmd_ch->vars, "VBJdhand");
        del_var(cmd_ch->vars, "VBJcurr");
        del_var(cmd_ch->vars, "VBJbet");
        return TRUE;
    }

    set_var(&cmd_ch->vars, "VBJdeck", deck);
    set_var(&cmd_ch->vars, "VBJphand", phand);
    set_var(&cmd_ch->vars, "VBJdhand", dhand);

    return TRUE;
}

const char *rainbow_colors[5] =
{
    "&R", "&Y", "&G", "&B", "&P"
};

SPECIAL_FUNC(spec_rainbow)
{
    CHAR_DATA *tch;
    char buf[MAX_INPUT_LENGTH];
    int x;

    if (type != SFT_COMMAND || cmd->do_fun != do_say)
        return FALSE;

    buf[0]='\0';
    for (x=0;x<strlen(arg);x++)
        sprintf(buf+strlen(buf), "%s%c", rainbow_colors[x%5], arg[x]);

    for (tch=cmd_ch->in_room->first_person;tch;tch=tch->next_in_room)
        if (cmd_ch!=tch && !IS_NPC(tch))
            break;

    if (!tch || cmd_ch==tch || IS_NPC(tch))
        return FALSE;

    for (tch=cmd_ch->in_room->first_person;tch;tch=tch->next_in_room)
        if (cmd_ch==tch)
            ch_printf(tch, "&WYou say '%s&W'\n\r", arg);
        else
            ch_printf(tch, "&W%s says '%s&W'\n\r", PERS(cmd_ch,tch), buf);

    return TRUE;
}

void base_berserk(CHAR_DATA *ch);
SPECIAL_FUNC(spec_BerserkerItem)
{
    OBJ_DATA *obj = (OBJ_DATA *)proc;

    if (type != SFT_UPDATE ||
        !obj->carried_by ||
        obj->wear_loc == WEAR_NONE)
        return FALSE;

    if (!who_fighting(obj->carried_by))
        return FALSE;

    if (is_affected(obj->carried_by, gsn_berserk))
        return FALSE;

    base_berserk(obj->carried_by);

    return TRUE;
}

SPECIAL_FUNC(spec_soap)
{
    OBJ_DATA *obj = (OBJ_DATA *)proc;
    AFFECT_DATA *paf, *paf_next;

    if (type != SFT_COMMAND || cmd->do_fun != do_use)
        return FALSE;

    if ( get_eq_char(cmd_ch, WEAR_HOLD) != obj )
        return FALSE;

    if ( !arg || !*arg || str_cmp(arg, "soap") )
        return FALSE;

    if (is_affected(cmd_ch, gsn_web))
    {
        for ( paf = cmd_ch->first_affect; paf; paf = paf_next )
        {
            paf_next = paf->next;

            if (paf->type != gsn_web)
                continue;

            affect_remove( cmd_ch, paf );
        }

        act(AT_PLAIN, "You wash some webbing off with $p.", cmd_ch, obj, NULL, TO_CHAR);
        act(AT_PLAIN, "$n washes some webbing off with $p.", cmd_ch, obj, NULL, TO_ROOM);
    }
    else
    {
        act(AT_PLAIN, "You give yourself a good lathering with $p.", cmd_ch, obj, NULL, TO_CHAR);
        act(AT_PLAIN, "$n gives $mself a good lathering with $p.", cmd_ch, obj, NULL, TO_ROOM);
    }

    if (--obj->value[0] <= 0)
    {
        act(AT_PLAIN, "That used up $p.", cmd_ch, obj, NULL, TO_CHAR);
        obj_from_char( obj );
        extract_obj( obj );
    }

    return TRUE;
}

SPECIAL_FUNC(spec_VideoPoker)
{
    return FALSE;
}

SPECIAL_FUNC(spec_EvilBlade)
{
    OBJ_DATA *obj = (OBJ_DATA *)proc;

    if ( obj )
        bug( "Obj with unfinished proc." );

    return FALSE;
}

SPECIAL_FUNC(spec_jive_box)
{
    OBJ_DATA *obj = (OBJ_DATA *)proc;

    if ( obj )
        bug( "Obj with unfinished proc." );

    return FALSE;
}

SPECIAL_FUNC(spec_BitterBlade)
{
    OBJ_DATA *obj = (OBJ_DATA *)proc;

    if ( obj )
        bug( "Obj with unfinished proc." );

    return FALSE;
}

SPECIAL_FUNC(spec_portal)
{
    OBJ_DATA *obj = (OBJ_DATA *)proc;

    if ( obj )
      bug( "Obj with unfinished proc." );

    return FALSE;
}

SPECIAL_FUNC(spec_scraps)
{
    OBJ_DATA *obj = (OBJ_DATA *)proc;

    if ( obj )
      bug( "Obj with unfinished proc." );

    return FALSE;
}

SPECIAL_FUNC(spec_antioch_grenade)
{
    OBJ_DATA *obj = (OBJ_DATA *)proc;

    if ( obj )
      bug( "Obj with unfinished proc." );

    return FALSE;
}

SPECIAL_FUNC(spec_GoodBlade)
{
    OBJ_DATA *obj = (OBJ_DATA *)proc;

    if ( obj )
      bug( "Obj with unfinished proc." );

    return FALSE;
}

SPECIAL_FUNC(spec_NeutralBlade)
{
    OBJ_DATA *obj = (OBJ_DATA *)proc;

    if ( obj )
      bug( "Obj with unfinished proc." );

    return FALSE;
}

SPECIAL_FUNC(spec_chainsaw)
{
    OBJ_DATA *obj = (OBJ_DATA *)proc;

    if ( obj )
      bug( "Obj with unfinished proc." );

    return FALSE;
}

SPECIAL_FUNC(spec_CrapTable)
{
    OBJ_DATA *obj = (OBJ_DATA *)proc;

    if ( obj )
      bug( "Obj with unfinished proc." );

    return FALSE;
}