/***************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************/
#include <glib.h>
#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <merc.h>
#include <recycle.h>
#include <olc.h>
#include <interp.h>
#include <fight.h>
#include <tables.h>
#include <power.h>
extern bool check_safe_imm args((CHAR_DATA *ch));
CHAR_DATA *get_char_area( CHAR_DATA *ch,char *argument)
{
char arg[MAX_INPUT_LENGTH];
CHAR_DATA *ach;
int number,count;
if ( (ach = get_char_room( ch, argument )) != NULL )
return ach;
number = number_argument( argument, arg );
count = 0;
for ( ach = char_list; ach != NULL; ach = ach->next )
{
if (ach->in_room->area != ch->in_room->area
|| !can_see( ch, ach ) || !is_name( arg, ach->name->str ))
continue;
if (++count == number)
return ach;
}
return ach;
}
CHAR_DATA *get_char_id( long id )
{
CHAR_DATA *wch;
for ( wch = char_list; wch != NULL ; wch = wch->next )
{
if ( wch->id == id ) return wch;
}
return NULL;
}
/*
* Move a char out of a room.
*/
void char_from_room( CHAR_DATA *ch )
{
OBJ_DATA *obj;
if ( ch->in_room == NULL )
{
bug( "Char_from_room: NULL.", 0 );
return;
}
if ( !IS_NPC(ch) )
--ch->in_room->area->nplayer;
if ( ( obj = get_eq_char( ch, WEAR_LIGHT ) ) != NULL
&& obj->item_type == ITEM_LIGHT
&& obj->value[2] != 0
&& ch->in_room->light > 0 )
--ch->in_room->light;
if ( ch == ch->in_room->people )
{
ch->in_room->people = ch->next_in_room;
}
else
{
CHAR_DATA *prev;
for ( prev = ch->in_room->people; prev; prev = prev->next_in_room )
{
if ( prev->next_in_room == ch )
{
prev->next_in_room = ch->next_in_room;
break;
}
}
if ( prev == NULL )
{
bug( "Char_from_room: ch not found.", 0 );
}
}
ch->in_room = NULL;
ch->next_in_room = NULL;
return;
}
/*
* Move a char into a room.
*/
void char_to_room( CHAR_DATA *ch, ROOM_INDEX_DATA *pRoomIndex )
{
OBJ_DATA *obj;
if ( pRoomIndex == NULL )
{
ROOM_INDEX_DATA *room;
bug( "Char_to_room: NULL.", 0 );
if ((room = get_room_index(ROOM_VNUM_TEMPLE)) != NULL)
char_to_room(ch,room);
return;
}
ch->in_room = pRoomIndex;
ch->next_in_room = pRoomIndex->people;
pRoomIndex->people = ch;
if ( !IS_NPC(ch) )
{
if (ch->in_room->area->empty)
{
ch->in_room->area->empty = FALSE;
ch->in_room->area->age = 0;
}
++ch->in_room->area->nplayer;
}
if ( ( obj = get_eq_char( ch, WEAR_LIGHT ) ) != NULL
&& obj->item_type == ITEM_LIGHT
&& obj->value[2] != 0 )
++ch->in_room->light;
//else if ( ( obj = get_eq_char( ch, WEAR_HOLD ) ) != NULL
//&& obj->item_type == ITEM_LIGHT
//&& obj->value[2] != 0 )
//++ch->in_room->light;
if (ch->loc_hp[6] > 0 && ch->in_room->blood < 1000) ch->in_room->blood += 1;
return;
}
/*
* Extract a char from the world.
*/
void extract_char( CHAR_DATA *ch, bool fPull )
{
CHAR_DATA *wch;
CHAR_DATA *familiar;
CHAR_DATA *wizard;
OBJ_DATA *obj;
OBJ_DATA *obj_next;
if ( ch == NULL ) return;
if ( ch->in_room == NULL )
{
bug( "Extract_char: NULL.", 0 );
return;
}
if ( fPull )
die_follower( ch );
stop_fighting( ch, TRUE );
for ( obj = ch->carrying; obj != NULL; obj = obj_next )
{
obj_next = obj->next_content;
extract_obj( obj );
}
if (ch->in_room != NULL)
char_from_room( ch );
if ( IS_NPC(ch) )
{
--ch->pIndexData->count;
//Clean the Pet Pointer from Master
if (ch->pet_master != NULL)
{
ch->pet_master->pet = NULL;
ch->pet_master = NULL;
}
}
else if ( ch->pcdata->chobj != NULL )
{
ch->pcdata->chobj->chobj = NULL;
ch->pcdata->chobj = NULL;
}
if ( !fPull )
{
char_to_room( ch, get_room_index( ROOM_VNUM_ALTAR ) );
return;
}
if ( ch->desc != NULL && ch->desc->original != NULL )
do_return( ch, "" );
if (ch->pet != NULL)
{
stop_fighting(ch->pet, TRUE);
extract_char(ch->pet,TRUE);
ch->pet = NULL;
}
if (!IS_NPC(ch))
{
for ( wch = char_list; wch != NULL; wch = wch->next )
{
if ( wch->reply == ch )
wch->reply = NULL;
if ( ch->mprog_target == wch )
wch->mprog_target = NULL;
}
}
if ( ch == char_list )
{
char_list = ch->next;
}
else
{
CHAR_DATA *prev;
for ( prev = char_list; prev != NULL; prev = prev->next )
{
if ( prev->next == ch )
{
prev->next = ch->next;
break;
}
}
if ( prev == NULL )
{
bug( "Extract_char: char not found.", 0 );
mudsetting->last_proc_logged = 51;
return;
}
}
if ( (wizard = ch->wizard) != NULL)
{
if (!IS_NPC(wizard)) wizard->pcdata->familiar = NULL;
ch->wizard = NULL;
}
if ( !IS_NPC(ch) )
{
if ((familiar = ch->pcdata->familiar) != NULL)
{
if (IS_NPC(familiar))
{
act("...$n slowly fades away to nothing.",familiar,NULL,NULL,TO_ROOM);
extract_char(familiar,TRUE);
}
familiar->wizard = NULL;
ch->pcdata->familiar = NULL;
}
if ((familiar = ch->pcdata->partner) != NULL)
ch->pcdata->partner = NULL;
if ((familiar = ch->pcdata->propose) != NULL)
ch->pcdata->propose = NULL;
for ( familiar = char_list; familiar != NULL; familiar = familiar->next)
{
if ( !IS_NPC(familiar) && familiar->pcdata->propose != NULL &&
familiar->pcdata->propose == ch )
familiar->pcdata->propose = NULL;
if ( !IS_NPC(familiar) && familiar->pcdata->partner != NULL &&
familiar->pcdata->partner == ch )
familiar->pcdata->partner = NULL;
}
}
else if (IS_NPC(ch) && ch->lord->len > 1)
{
for ( wch = char_list; wch != NULL ; wch = wch->next )
{
if (IS_NPC(wch)) continue;
if (str_cmp(wch->name->str, ch->lord->str)) continue;
if (wch->pcdata->followers > 0) wch->pcdata->followers--;
}
}
if ( ch->desc )
ch->desc->character = NULL;
free_char( ch );
mudsetting->last_proc_logged = 52;
return;
}
/*
* Find a char in the room.
*/
CHAR_DATA *get_char_room( CHAR_DATA *ch, char *argument )
{
char arg[MAX_INPUT_LENGTH];
CHAR_DATA *rch;
int number;
int count;
number = number_argument( argument, arg );
count = 0;
if ( !str_cmp( arg, "self" ) && (IS_NPC(ch) || ch->pcdata->chobj == NULL))
return ch;
for ( rch = ch->in_room->people; rch != NULL; rch = rch->next_in_room )
{
if ( !IS_NPC(rch) && IS_HEAD(rch, LOST_HEAD) ) continue;
else if ( !IS_NPC(rch) && IS_EXTRA(rch, EXTRA_OSWITCH) ) continue;
else if ( !can_see( ch, rch ) || ( !is_name( arg, rch->name->str ) &&
!is_name(arg, unknown_name(rch,ch)) &&
( IS_NPC(rch) || !is_name( arg, rch->morph->str ))))
continue;
/* so you don't greet your damn self */
if (!IS_NPC(rch) && is_name(arg, unknown_name(rch,ch)) && rch == ch)
continue;
if ( ++count == number )
return rch;
}
return NULL;
}
/*
* Find a char in the world.
*/
CHAR_DATA *get_char_world( CHAR_DATA *ch, char *argument )
{
char arg[MAX_INPUT_LENGTH];
CHAR_DATA *wch;
int number;
int count;
if ( ( wch = get_char_room( ch, argument ) ) != NULL )
return wch;
number = number_argument( argument, arg );
count = 0;
for ( wch = char_list; wch != NULL ; wch = wch->next )
{
if ( !IS_NPC(wch) && IS_HEAD(wch, LOST_HEAD) ) continue;
else if ( !IS_NPC(wch) && IS_EXTRA(wch, EXTRA_OSWITCH) ) continue;
else if ( !can_see( ch, wch ) || ( !is_name( arg, wch->name->str ) &&
( IS_NPC(wch) || !is_name( arg, wch->morph->str ))))
continue;
if ( ++count == number )
return wch;
}
return NULL;
}
CHAR_DATA *get_char_world2( CHAR_DATA *ch, char *argument )
{
CHAR_DATA *wch;
if (argument[0] == '\0')
return NULL;
for ( wch = char_list; wch != NULL ; wch = wch->next )
{
if ( IS_NPC(wch) && !str_cmp( argument, wch->short_descr->str ) )
return wch;
}
return NULL;
}
void gain_exp( CHAR_DATA *ch, int gain )
{
CHAR_DATA *mount = NULL;
CHAR_DATA *master = NULL;
if ( IS_NPC(ch) && (mount = ch->mount) != NULL && !IS_NPC(mount))
{
if ( (master = ch->master) == NULL || master != mount )
mount->exp += gain;
}
if ( !IS_IMMORTAL(ch) )
ch->exp += gain;
return;
}
/*
* Regeneration stuff.
*/
int hit_gain( CHAR_DATA *ch )
{
double gain;
double conamount;
//check for linky dead people
if (!IS_NPC(ch) && ch->desc == NULL)
return 0;
if ( IS_NPC(ch) )
{
gain = ch->level;
}
else
{
gain = number_range( 10, 20 );
if ((conamount = (get_curr_con(ch)+1)) > 1)
{
switch ( ch->position )
{
case POS_MEDITATING: gain *= conamount * 0.5; break;
case POS_SLEEPING: gain *= conamount; break;
case POS_RESTING: gain *= conamount * 0.5; break;
}
}
if ( ch->pcdata->condition[COND_FULL] == 0 && !IS_HERO(ch) )
gain *= 0.25;
if ( ch->pcdata->condition[COND_THIRST] == 0 && !IS_HERO(ch) )
gain *= 0.25;
}
if ( IS_ITEMAFF(ch, ITEMA_REGENERATE) )
{
act("{G$n regenerates{x.",ch,NULL,NULL,TO_ROOM);
act("{GYou regenerate.{x",ch,NULL,NULL,TO_CHAR);
spell_clot(skill_lookup("clot"), AUTO_REGEN, ch, ch);
spell_mend(skill_lookup("mend"), AUTO_REGEN, ch, ch);
if (number_percent() < 50) gain *= 1.20; /* 50% of a 20% */
else if (number_percent() < 50) gain *= 1.40; /* 25% of a 40% */
else if (number_percent() < 50) gain *= 1.80; /* 12.5% of a 80% */
else if (number_percent() < 50) gain *= 2.60; /* 6.25% of a 160% */
else if (number_percent() < 50) gain *= 5; /* 3.125% of a 400% */
}
if ( IS_AFFECTED(ch, AFF_POISON) || IS_AFFECTED(ch, AFF_FLAMING))
gain *= 0.25;
if ( IS_AFFECTED(ch, AFF_POISON) )
gain *= 0.25;
if (IS_CLASS(ch,CLASS_MAGE))
{
/* if they are tapping the caren, give SUPER Heal! */
if (IS_SET(ch->act,ACT_TAPPING))
{
send_to_char("You feel the life force from the caern enter your body.\n\r",ch);
gain *= 4;
}
}
if (ch->on != NULL && ch->on->item_type == ITEM_FURNITURE)
gain = gain * ch->on->value[3] / 90;
if (IS_CLASS(ch, CLASS_VAMPIRE)) return 0;
return UMIN((int)gain, ch->max_hit - ch->hit);
}
int mana_gain( CHAR_DATA *ch )
{
double gain;
double intamount;
//
//check for linky dead people
if (!IS_NPC(ch) && ch->desc == NULL)
return 0;
if ( IS_NPC(ch) )
{
gain = ch->level;
}
else
{
if (IS_CLASS(ch, CLASS_VAMPIRE)) return 0;
gain = number_range( 10, 20 );
if ((intamount = (get_curr_int(ch)+1)) > 1)
{
switch ( ch->position )
{
case POS_MEDITATING: gain *= intamount * ch->level; break;
case POS_SLEEPING: gain *= intamount; break;
case POS_RESTING: gain *= intamount * 0.5; break;
}
}
if ( !IS_HERO(ch) && ch->pcdata->condition[COND_THIRST] == 0 )
gain *= 0.25;
}
if ( IS_AFFECTED( ch, AFF_POISON ) || IS_AFFECTED(ch, AFF_FLAMING) )
gain *= 0.25;
if ( IS_AFFECTED(ch, AFF_POISON) )
gain *= 0.25;
if (IS_CLASS(ch,CLASS_MAGE))
{
gain *= number_range(8,14);
/* if they are tapping the caren, give SUPER MANA! */
if (IS_SET(ch->act,ACT_TAPPING))
{
send_to_char("You feel the life force from the caern enter your body.\n\r",ch);
gain *= 4;
}
}
if (ch->on != NULL && ch->on->item_type == ITEM_FURNITURE)
gain = gain * ch->on->value[3] / 90;
return UMIN((int)gain, ch->max_mana - ch->mana);
}
int move_gain( CHAR_DATA *ch )
{
double gain;
double dexamount;
if ( IS_NPC(ch) )
{
gain = ch->level;
}
else
{
if (IS_CLASS(ch, CLASS_VAMPIRE)) return 0;
gain = number_range( 10, 20 );
if ((dexamount = (get_curr_dex(ch)+1)) > 1)
{
switch ( ch->position )
{
case POS_MEDITATING: gain *= dexamount * 0.5; break;
case POS_SLEEPING: gain *= dexamount; break;
case POS_RESTING: gain *= dexamount * 0.5; break;
}
}
if ( !IS_HERO(ch) && ch->pcdata->condition[COND_THIRST] == 0 )
gain *= 0.25;
}
if ( IS_AFFECTED(ch, AFF_POISON) || IS_AFFECTED(ch, AFF_FLAMING) )
gain *= 0.25;
if ( IS_AFFECTED(ch, AFF_POISON) )
gain *= 0.25;
if (ch->on != NULL && ch->on->item_type == ITEM_FURNITURE)
gain = gain * ch->on->value[3] / 90;
return UMIN((int)gain, ch->max_move - ch->move);
}
void gain_condition( CHAR_DATA *ch, int iCond, int value )
{
int condition;
/*
* If the player is in a Imm made safe room.. no thirst
*/
if (check_safe_imm(ch))
return;
if ( value == 0 || IS_NPC(ch) )
return;
if (!IS_NPC(ch) && IS_HERO(ch) && !IS_CLASS(ch, CLASS_VAMPIRE)
&& iCond != COND_DRUNK)
return;
condition = ch->pcdata->condition[iCond];
if (!IS_NPC(ch) && !IS_CLASS(ch, CLASS_VAMPIRE) )
ch->pcdata->condition[iCond] = URANGE( 0, condition + value, 50 );
else
ch->pcdata->condition[iCond] = URANGE( 0, condition + value, 100 + ch->pcdata->stats[UNI_BLOOD_MAX]);
if ( ch->pcdata->condition[iCond] == 0 )
{
switch ( iCond )
{
case COND_FULL:
if (!IS_CLASS(ch, CLASS_VAMPIRE))
{
send_to_char( "You are REALLY hungry. You become weary and tired.\n\r", ch );
ch->move = ch->move - 10;
act( "You hear $n's stomach rumbling.", ch, NULL, NULL, TO_ROOM );
}
break;
case COND_THIRST:
if (!IS_CLASS(ch, CLASS_VAMPIRE))
{
send_to_char( "You are REALLY thirsty. You become weary and tired.\n\r", ch );
ch->move = ch->move - 10;
}
else if (ch->hit > 0)
{
send_to_char( "You are DYING from lack of blood!\n\r", ch );
act( "$n gets a hungry look in $s eyes.", ch, NULL, NULL, TO_ROOM );
ch->hit -= (int)((double)ch->hit * 0.05); /* subtract 5% hp */
/* ch->hit = ch->hit - number_range(100,300); */
if (number_percent() <= ch->beast && ch->beast > 0) vamp_rage(ch);
if (!IS_VAMPAFF(ch, VAM_FANGS)) power_fangs(ch,ch,"");
if (number_percent() <= 25 && ch->fighting == NULL)
{
send_to_char( "Need...more...BLOOD...\n\r", ch );
do_sleep(ch,"");
WAIT_STATE( ch, 24 );
}
}
break;
case COND_DRUNK:
if ( condition != 0 )
send_to_char( "You are sober.\n\r", ch );
break;
}
}
else if ( ch->pcdata->condition[iCond] < 10 )
{
switch ( iCond )
{
case COND_FULL:
if (!IS_CLASS(ch, CLASS_VAMPIRE))
send_to_char( "You feel hungry.\n\r", ch );
break;
case COND_THIRST:
if (!IS_CLASS(ch, CLASS_VAMPIRE))
send_to_char( "You feel thirsty.\n\r", ch );
else
{
send_to_char( "You crave blood.\n\r", ch );
if (number_range(1,1000) <= ch->beast && ch->beast > 0) vamp_rage(ch);
if (number_percent() > (ch->pcdata->condition[COND_THIRST]+75)
&& !IS_VAMPAFF(ch, VAM_FANGS)) power_fangs(ch,ch,"");
}
break;
}
}
return;
}