/*************************************************************************** * 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; }