/** * \file limits.c * Gain Control Module * * This module is to provides limitiations on skill use, and deals with updates * on rooms, connection status, sleep and movement. * * Copyright 2005, Mary C. Huston, All rights reserved. * Copyright (C) 2004, Shadows of Isildur: Traithe * * The program(s) may be used and/or copied only with written * permission or in accordance with the terms and conditions * stipulated in the license from DIKU GAMMA (0.0) and SOI. * * \author Mary Huston * \author Email: auroness@gmail.com * ****************************************************************************** */ #include <stdio.h> #include <time.h> #include <ctype.h> #include <string.h> #include "structs.h" #include "protos.h" #include "utils.h" #include "decl.h" #include "math.h" int move_gain (CHAR_DATA *ch) { int gain; int move_rate; int moves_gained; /* Move_rate is 100 moves per 5 mins ( * 10000 for granularity ) */ move_rate = 10000 * GET_CON (ch) * UPDATE_PULSE / ( 12 * 16 ); /* if GET_CON < 12 then move_rate < 10000 */ /* if GET_CON > 12 then move_rate > 10000 */ /* Higher con means you can recover faster */ gain = move_rate; /* base value */ switch ( GET_POS (ch) ) { /* changes due to position */ case POSITION_SLEEPING: gain += (gain); break; case POSITION_RESTING: gain += (gain/2); break; case POSITION_SITTING: gain += (gain/4); break; default: gain = (gain + 0); break; } /* changes due to hunger/thirst */ if( !ch->hunger || !ch->thirst ) gain += (gain/2); if ( ch->move_points < 0 ) ch->move_points = 0; /* granularity */ moves_gained = gain/10000; ch->move_points += moves_gained; /* special case for Guests in OOC rooms */ if ( IS_SET(ch->room->room_flags, OOC) && !IS_SET (ch->flags, FLAG_GUEST) ) moves_gained = 0; return moves_gained; } int sleep_needed_in_seconds (CHAR_DATA *ch) { if ( !ch->pc ) return 0; return ch->pc->sleep_needed / 100000; } void sleep_credit (CHAR_DATA *ch) { /* We're aiming for straight credit for sleeping, which will be 5 seconds per update if UPDATE_PULSE is 5 * 4 (5 seconds) */ if ( !ch->pc || !ch->desc ) return; ch->pc->sleep_needed -= (UPDATE_PULSE / 4) * 100000; if ( ch->pc->sleep_needed < 0 ) ch->pc->sleep_needed = 0; } void sleep_need (CHAR_DATA *ch) { int need; if ( !ch->pc ) return; else /* To enable sleep, get rid of this next return */ return; /* 5 * 60 is RL seconds (5 RL minutes sleep need per mud day) */ /* sleep needed is called (60 * 60 * 24) / (UPDATE_PULSE/4) times a mud day. */ /* 10000 is stuck in for granularity */ /* If sleep needed is too long, assume that staff has set it this way. */ if ( ch->pc->sleep_needed > 10 * 60 * 100000 ) return; need = 5 * 60 * 100000 * (UPDATE_PULSE / 4) / (60 * 60 * 24); ch->pc->sleep_needed += need; if ( ch->pc->sleep_needed > 10 * 60 * 100000 ) ch->pc->sleep_needed = 10 * 60 * 100000; } void check_linkdead (void) { CHAR_DATA *tch = NULL; for ( tch = character_list; tch; tch = tch->next ) { if ( tch->deleted ) continue; if ( IS_NPC(tch) || tch->desc || !IS_MORTAL(tch) || !tch->room ) continue; if ( tch->pc->time_last_activity + PLAYER_DISCONNECT_SECS < mud_time ) { do_quit (tch, "", 3); } } } void check_idling (DESCRIPTOR_DATA *d) { /* Unmark people who aren't really idle */ if ( d->idle && d->time_last_activity + PLAYER_IDLE_SECS > mud_time ) { d->idle = 0; return; } if ( d->original ) return; if ( !d->character && d->time_last_activity + DESCRIPTOR_DISCONNECT_SECS < mud_time && (d->connected <= CON_ACCOUNT_MENU || d->connected == CON_PENDING_DISC) ) { close_socket (d); return; } /* Disconnect those people idle for too long */ if ( d->idle && d->time_last_activity + PLAYER_DISCONNECT_SECS < mud_time ) { if ( d->character && (IS_NPC(d->character) || !IS_MORTAL(d->character)) ) return; if ( d->original ) return; /* Idle PCs in the chargen process */ if ( d->character && !d->character->room ) { close_socket (d); } if ( d->character && d->connected && d->character->room ) do_quit (d->character, "", 3); return; } /* Warn people who are just getting to be idle */ if ( !d->idle && d->time_last_activity + PLAYER_IDLE_SECS < mud_time ) { if ( d->character ) { if ( d->connected == CON_PLYNG ) SEND_TO_Q ("Your thoughts begin to drift. #2(Idle)#0\n\r", d); else SEND_TO_Q ("\n\rYour attention is required to prevent disconnection from the server. #2(Idle)#0\n\r", d); } d->idle = 1; } } void check_idlers () { DESCRIPTOR_DATA *d, *d_next; for ( d = descriptor_list; d; d = d_next ) { d_next = d->next; check_idling (d); } } /* Update both PC's & NPC's and objects*/ void point_update (void) { int cycle_count = 0; int roll = 0; int i = 0; int damage = 0; char buf [MAX_STRING_LENGTH] = {'\0'}; char buf2 [MAX_STRING_LENGTH] = {'\0'}; char *temp_arg1 = NULL; char *temp_arg2 = NULL; CHAR_DATA *ch = NULL; CHAR_DATA *tch = NULL; CHAR_DATA *next_ch = NULL; ROOM_DATA *room = NULL; AFFECTED_TYPE *af = NULL; WOUND_DATA *wound = NULL; WOUND_DATA *next_wound = NULL; struct time_info_data healing_time; struct time_info_data bled_time; struct time_info_data playing_time; static int reduceIntox = 0; cycle_count = 0; mud_time_str = timestr(mud_time_str); for ( i = 0; i <= 99; i++ ) zone_table[i].player_in_zone = 0; for (ch = character_list; ch; ch = next_ch ) { if ( !ch ) continue; next_ch = ch->next; if ( ch->deleted ) continue; if ( !ch->room ) continue; if ( !IS_NPC (ch) && ch->room ) zone_table[ch->room->zone].player_in_zone++; room = ch->room; *ch->short_descr = tolower(*ch->short_descr); if ( IS_SET (ch->act, ACT_VEHICLE) ) { if ( room->sector_type == SECT_REEF ) { for ( tch = character_list; tch; tch = tch->next ) { if ( tch->deleted ) continue; if ( tch->vehicle == ch ) send_to_char ("The boat shudders and you hear the sides of the " "ship scrape against\n\r" "something.\n\r", tch); } send_to_char ("Ouch! You're scraping against the reef!\n\r", ch); if ( weaken (ch, 10, 0, "boat in REEF") ) /* 10 hits for scraping the reef */ continue; } } if ( !ch ) continue; if ( GET_POS (ch) >= SLEEP ) { if ( ch->pc ) { if ( (af = get_affect (ch, MAGIC_AFFECT_PARALYSIS)) ) { if ( GET_POS (ch) == STAND ) { send_to_char ("You fall down.\n", ch); act ("$n falls down.", FALSE, ch, 0, 0, TO_ROOM); } else if ( GET_POS (ch) == SIT ) { send_to_char ("You collapse.\n", ch); act ("$n collapses.", FALSE, ch, 0, 0, TO_ROOM); } GET_POS (ch) = REST; } if ( (GET_POS (ch) == REST || GET_POS (ch) == SIT) && sleep_needed_in_seconds (ch) > 7 * 60 && IS_MORTAL (ch) && !number (0, 8) && !get_second_affect (ch, SPA_STAND, NULL) ) { act ("$n falls alseep.", FALSE, ch, 0, 0, TO_ROOM); GET_POS (ch) = SLEEP; } if ( sleep_needed_in_seconds (ch) == 300 && IS_MORTAL (ch) ) { send_to_char ("You are feeling drowsy.\n", ch); /* Adding this is 1 sec. If we don't do this, the drowsy message appears every 5 seconds. */ ch->pc->sleep_needed += 100000; } else if ( sleep_needed_in_seconds (ch) == 350 && IS_MORTAL (ch) ) { send_to_char ("You are feeling sleepy.\n", ch); ch->pc->sleep_needed += 100000; } else if ( sleep_needed_in_seconds (ch) == 400 && IS_MORTAL (ch) ) { send_to_char ("You are about to fall asleep.\n", ch); ch->pc->sleep_needed += 100000; } else if ( GET_POS (ch) >= REST && GET_POS (ch) != FIGHT && sleep_needed_in_seconds (ch) > 6 * 60 && number (0, 25) == 25 && IS_MORTAL (ch) && ch->desc && ch->desc->original == ch ) { if ( number (0, 1) ) act ("You stifle a yawn.", FALSE, ch, 0, 0, TO_CHAR); else { if ( get_affect (ch, MAGIC_HIDDEN) && would_reveal (ch) ) { remove_affect_type (ch, MAGIC_HIDDEN); act ("$n reveals $mself.", TRUE, ch, 0, 0, TO_ROOM); } act ("You yawn.", FALSE, ch, 0, 0, TO_CHAR); act ("$n yawns.", FALSE, ch, 0, 0, TO_ROOM); } } if ( GET_POS (ch) == SLEEP ) sleep_credit (ch); else if ( IS_MORTAL (ch) ) sleep_need (ch); } else if ( GET_POS (ch) == POSITION_SLEEPING && ch->desc && ch->pc && ch->pc->dreams && !number (0, 5) ) dream (ch); if ( GET_MOVE (ch) < GET_MAX_MOVE (ch) ) GET_MOVE (ch) = MIN (GET_MOVE (ch) + move_gain (ch), GET_MAX_MOVE (ch)); } if ( !ch ) continue; if ( ch->skills [SKILL_EMPATHIC_HEAL] || get_affect(ch, MAGIC_AFFECT_REGENERATION) ) { if (ch->damage) { healing_time = real_time_passed (time(0) - ch->lastregen, 0); if (healing_time.minute >= (BASE_SPECIAL_HEALING - ch->con/6)) { roll = dice(1,100); if (GET_POS(ch) == POSITION_SLEEPING) roll -= 20; if (GET_POS(ch) == POSITION_RESTING) roll -= 10; if (GET_POS(ch) == POSITION_SITTING) roll -= 5; if ( roll <= (ch->con * 4) ) { if ( roll % 5 == 0 ) ch->damage -= 2; else ch->damage -= 1; } ch->lastregen = time(0); } } } else { if (ch->damage) { healing_time = real_time_passed (time(0) - ch->lastregen, 0); if (healing_time.minute >= (BASE_PC_HEALING - ch->con/6)) { roll = dice(1,100); if (GET_POS(ch) == POSITION_SLEEPING) roll -= 20; if (GET_POS(ch) == POSITION_RESTING) roll -= 10; if (GET_POS(ch) == POSITION_SITTING) roll -= 5; if ( roll <= (ch->con * 4) ) { if ( roll % 5 == 0 ) ch->damage -= 2; else ch->damage -= 1; } ch->lastregen = time(0); } } } if ( !ch ) continue; if ( GET_POS (ch) == POSITION_STUNNED ) { if ( (time(0) - ch->laststuncheck) >= number(15,20) ) { ch->laststuncheck = time(0); GET_POS (ch) = REST; send_to_char ("You shake your head vigorously, recovering from your stun.\n", ch); snprintf (buf, MAX_STRING_LENGTH, "$n shakes $s head vigorously, seeming to recover."); act (buf, FALSE, ch, 0, 0, TO_ROOM); if ( IS_NPC(ch) ) do_stand(ch, "", 0); } } if ( !ch ) continue; if ( GET_POS (ch) == POSITION_UNCONSCIOUS ) { healing_time = real_time_passed (time(0) - ch->knockedout, 0); if (healing_time.minute >= 5) { GET_POS (ch) = REST; send_to_char ("Groaning groggily, you regain consciousness.\n", ch); snprintf (buf, MAX_STRING_LENGTH, "Groaning groggily, $n regains consciousness."); act (buf, FALSE, ch, 0, 0, TO_ROOM); if ( IS_NPC(ch) ) do_stand(ch, "", 0); } } if ( !ch ) continue; if (reduceIntox == 3) { if ( (ch->intoxication > 0) && (!--ch->intoxication)){ send_to_char ("You are sober.\n", ch); reduceIntox = 0; } } else { reduceIntox++; } if ( !ch ) continue; if ( !IS_NPC (ch) && ch->pc->app_cost && ch->desc ) { playing_time = real_time_passed (time(0) - ch->time.logon + ch->time.played, 0); if ( playing_time.hour >= 10 && ch->desc->account ) { ch->desc->account->roleplay_points -= ch->pc->app_cost; if ( ch->desc->account->roleplay_points < 0 ) ch->desc->account->roleplay_points = 0; save_account (ch->desc->account); ch->pc->app_cost = 0; save_char (ch, TRUE); } } if ( !IS_NPC (ch) && IS_SET (ch->plr_flags, NEW_PLAYER_TAG) ) { playing_time = real_time_passed (time(0) - ch->time.logon + ch->time.played, 0); if ( playing_time.hour > 12 ) { REMOVE_BIT (ch->plr_flags, NEW_PLAYER_TAG); act ("You've been playing for over 12 hours, now; the #2(new player)#0 tag on your long description has been removed. Once again, welcome - have fun, and best of luck in your travels!\n", FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT); } } if ( !ch ) continue; for (wound = ch->wounds; wound; wound = next_wound ) { if ( !ch->wounds ) break; next_wound = wound->next; damage += wound->damage; healing_time = real_time_passed (time(0) - wound->lasthealed, 0); bled_time = real_time_passed (time(0) - wound->lastbled, 0); if (IS_MORTAL(ch) && bled_time.minute >= BLEEDING_INTERVAL && wound->bleeding) { ch->damage += wound->bleeding; wound->lastbled = time(0); if ( wound->bleeding > 0 && wound->bleeding <= 3 ) { temp_arg1 = expand_wound_loc(wound->location); temp_arg2 = char_short(ch); snprintf (buf, MAX_STRING_LENGTH, "#1Blood continues to seep from a %s %s on your %s.#0", wound->severity, wound->name, temp_arg1); snprintf (buf2, MAX_STRING_LENGTH, "Blood continues to seep from a %s %s on #5%s#0's %s.", wound->severity, wound->name, temp_arg2, temp_arg1); } else if ( wound->bleeding > 3 && wound->bleeding <= 6 ) { temp_arg1 = expand_wound_loc(wound->location); temp_arg2 = char_short(ch); snprintf (buf, MAX_STRING_LENGTH, "#1Blood flows from a %s %s on your %s.#0", wound->severity, wound->name, temp_arg1); snprintf (buf2, MAX_STRING_LENGTH, "Blood flows from a %s %s on #5%s#0's %s.", wound->severity, wound->name, temp_arg2, temp_arg1); } else if ( wound->bleeding > 6 && wound->bleeding <= 9 ) { temp_arg1 = expand_wound_loc(wound->location); temp_arg2 = char_short(ch); snprintf (buf, MAX_STRING_LENGTH, "#1Blood flows heavily from a %s %s on your %s!#0", wound->severity, wound->name, temp_arg1); snprintf (buf2, MAX_STRING_LENGTH, "Blood flows heavily from a %s %s on #5%s#0's %s!", wound->severity, wound->name, temp_arg2, temp_arg1); } else if ( wound->bleeding > 9 ) { temp_arg1 = expand_wound_loc(wound->location); temp_arg2 = char_short(ch); snprintf (buf, MAX_STRING_LENGTH, "#1Blood gushes from a %s %s on your %s!#0", wound->severity, wound->name, temp_arg1); snprintf (buf2, MAX_STRING_LENGTH, "Blood gushes from a %s %s on #5%s#0's %s!", wound->severity, wound->name, temp_arg2, temp_arg1); } act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT); act (buf2, FALSE, ch, 0, 0, TO_ROOM | TO_ACT_FORMAT); if ( IS_SET (ch->plr_flags, NEW_PLAYER_TAG) ) act ("#6To stop the bleeding before it's too late, type BIND.#0", FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT); if ( general_damage (ch, wound->bleeding) ) continue; } if ( ch->skills [SKILL_EMPATHIC_HEAL] || get_affect(ch, MAGIC_AFFECT_REGENERATION) ) { if (healing_time.minute >= (BASE_SPECIAL_HEALING + (wound->damage/3) - GET_CON(ch)/7 - wound->healerskill/20)) { wound->lasthealed = time(0); if ( GET_POS(ch) != POSITION_FIGHTING && !IS_SET (ch->room->room_flags, OOC) ) natural_healing_check(ch, wound); } } else { if (healing_time.minute >= (BASE_PC_HEALING + (wound->damage/3) - GET_CON(ch)/7) - wound->healerskill/20) { wound->lasthealed = time(0); if ( GET_POS(ch) != POSITION_FIGHTING && !IS_SET (ch->room->room_flags, OOC) ) natural_healing_check(ch, wound); } } } if ( (af = get_affect (ch, MAGIC_CRAFT_DELAY)) ) { if ( time(0) >= af->a.spell.modifier ) { send_to_char ("#6OOC: Your craft delay timer has expired. You may resume crafting delayed items.#0\n", ch); remove_affect_type (ch, MAGIC_CRAFT_DELAY); } } if ( ch->damage < 0 ) ch->damage = 0; } /* for */ } void hourly_update (void) { int current_time = 0; int hours = 0; int nomsg = 0; CHAR_DATA *ch = NULL; CHAR_DATA *next_ch = NULL; OBJ_DATA *obj = NULL; OBJ_DATA *objj = NULL; OBJ_DATA *next_thing2 = NULL; ROOM_DATA *room = NULL; CHARM_DATA *ench = NULL; NEGOTIATION_DATA *neg = NULL; NEGOTIATION_DATA *new_list = NULL; NEGOTIATION_DATA *tmp_neg = NULL; char your_buf [MAX_STRING_LENGTH] = {'\0'}; char room_buf [MAX_STRING_LENGTH] = {'\0'}; char room_msg_buf [MAX_STRING_LENGTH] = {'\0'}; current_time = time (NULL); if ( time_info.hour >= 8 && time_info.hour <= 17 ) add_second_affect (SPA_CORONAN_ARENA, 2, NULL, NULL, NULL, 0); for ( ch = character_list; ch; ch = next_ch ) { next_ch = ch->next; if ( ch->deleted || !ch->room ) continue; for ( ench = ch->charms; ench; ench = ench->next ) { ench->current_hours--; if ( ench->current_hours <= 0 ) remove_charm(ch, ench); } if ( IS_NPC (ch) && IS_SET (ch->flags, FLAG_KEEPER) && ch->shop ) { neg = ch->shop->negotiations; new_list = NULL; while ( neg ) { tmp_neg = neg->next; if ( neg->time_when_forgotten <= current_time ) mem_free (neg); else { neg->next = new_list; new_list = neg; } neg = tmp_neg; } ch->shop->negotiations = new_list; } if ( !IS_NPC (ch) ) { if ( !IS_SET (ch->room->room_flags, OOC) ) hunger_thirst_process (ch); } trigger (ch, "", TRIG_HOUR); } for ( obj = object_list; obj; obj = obj->next ) { if ( obj->deleted ) continue; /* Mob jailbags need to disappear after a time */ if ( obj->virtual == VNUM_JAILBAG && obj->obj_timer && --obj->obj_timer == 0 ) extract_obj (obj); else if ( IS_SET (obj->obj_flags.extra_flags, ITEM_TIMER) && --obj->obj_timer <= 0 ) { room = (obj->in_room == NOWHERE ? NULL : vtor (obj->in_room)); if ( obj->carried_by ) act ("$p decays in your hands.", FALSE, obj->carried_by, obj, 0, TO_CHAR); else if ( room && room->people ) { act ("$p gradually decays away.", TRUE, room->people, obj, 0, TO_ROOM); act ("$p gradually decays away.", TRUE, room->people, obj, 0, TO_CHAR); } for( objj = obj->contains; objj; objj = next_thing2) { next_thing2 = objj->next_content; /* Next in inventory */ if ( obj->virtual == VNUM_CORPSE ) { SET_BIT (objj->obj_flags.extra_flags, ITEM_TIMER); objj->obj_timer = 12; /* Stuff from corpses lasts /* 3 RL hours, unless handled by a PC. */ } obj_from_obj (&objj, 0); if (obj->in_obj) obj_to_obj(objj,obj->in_obj); else if (obj->carried_by) obj_to_room(objj,obj->carried_by->in_room); else if (obj->in_room != NOWHERE) obj_to_room(objj,obj->in_room); else extract_obj (obj); } extract_obj (obj); } else if ( GET_ITEM_TYPE (obj) == ITEM_LIGHT && obj->o.light.on && obj->o.light.hours ) { obj->o.light.hours--; hours = obj->o.light.hours; if ( !(ch = obj->carried_by) ) ch = obj->equiped_by; switch ( hours ) { case 0: strcpy (your_buf, "Your $o burns out."); strcpy (room_buf, "$n's $o burns out."); strcpy (room_msg_buf, "$p burns out."); break; case 1: strcpy (your_buf, "Your $o is just a dim flicker now."); strcpy (room_buf, "$n's $o is just a dim flicker now."); strcpy (room_msg_buf, "$p is just a dim flicker now."); break; case 2: strcpy (your_buf, "Your $o begins to burn low."); strcpy (room_buf, "$n's $o begins to burn low."); strcpy (room_msg_buf, "$p begins to burn low."); break; case 10: strcpy (your_buf, "Your $o sputters."); strcpy (room_buf, "$n's $o sputters."); strcpy (room_msg_buf, "$p sputters."); break; default: nomsg = 1; break; } if ( hours == 0 || (!is_name_in_list ("candle", obj->name) && !nomsg) ) { if ( ch ) { act (your_buf, FALSE, ch, obj, 0, TO_CHAR); act (room_buf, FALSE, ch, obj, 0, TO_ROOM); } if ( obj->in_room && (room = vtor (obj->in_room)) && room->people ) { act (room_msg_buf, FALSE, room->people, obj, 0, TO_ROOM); act (room_msg_buf, FALSE, room->people, obj, 0, TO_CHAR); } } if ( obj->o.light.hours > 0 ) continue; if ( is_name_in_list ("candle", obj->name) ) extract_obj (obj); } if((obj->morphTime) && obj->morphTime < current_time) morph_obj(obj); } } int remove_room_affect (ROOM_DATA *room, int type) { AFFECTED_TYPE *af; AFFECTED_TYPE *free_af; if ( !room->affects ) return 0; if ( room->affects->type == type ) { free_af = room->affects; room->affects = free_af->next; mem_free (free_af); return 1; } for ( af = room->affects; af->next; af = af->next ) if ( af->next->type == type ) { free_af = af->next; af->next = free_af->next; mem_free (free_af); return 1; } return 0; } void room_affect_wearoff (ROOM_DATA *room, int type) { if ( !remove_room_affect (room, type) ) return; switch ( type ) { case MAGIC_ROOM_CALM: if ( room ) send_to_room ("Slowly, the sense of peace dissipates, and things return to normal.\n", room->virtual); else send_to_all ("The sense of peace everwhere fades.\n\r"); break; case MAGIC_ROOM_LIGHT: if ( room ) send_to_room ("The unnatural light emanations fade.\n\r", room->virtual); else send_to_all ("The unnatural light emanations fade from the land.\n\r"); break; case MAGIC_ROOM_DARK: if ( room ) send_to_room ("The unnatural darkness fades away.\n\r", room->virtual); else send_to_all ("The unnatural darkness fades from the land.\n\r"); break; case MAGIC_WORLD_SOLAR_FLARE: if ( room ) send_to_room ("The localized solar flare has ended.\n\r", room->virtual); else send_outside ("The ball of flame in the sky slowly dies out.\n\r"); break; } } void room_update (void) { /* Expire affects on rooms */ /******* needs lots of work ******************* ******** rooms don't ahve affects, so the code doens't work AFFECTED_TYPE room_affect; for ( room = full_room_list; room; room = room->lnext ) { for ( room_affect = room->affects; room_affect; room_affect = next_room_affect ) { next_room_affect = room_affect->next; if ( room_affect->type >= MAGIC_SMELL_FIRST && room_affect->type <= MAGIC_SMELL_LAST ) continue; if ( room_affect->type == MAGIC_ROOM_FIGHT_NOISE ) continue; if ( room_affect->a.room.duration > 0 ) room_affect->a.room.duration--; if ( !room_affect->a.room.duration ) room_affect_wearoff (room, room_affect->type); } } *****************************/ return; } /**** skill_use returns a 0 for no effect or failure, 1 for success-no skill gain, 2 for success-with skill gain ***/ int skill_use (CHAR_DATA *ch, int skill, int diff_mod) { double roll = 0; int lv = 0; int cap = 0; int skill_lev = 0; int min = 0; int max = 0; OBJ_DATA *obj =NULL; AFFECTED_TYPE *af = NULL; if ( !real_skill (ch, skill) ) return 0; lv = calc_lookup (ch, REG_LV, skill); cap = calc_lookup (ch, REG_CAP, skill); cap = MIN(cap, 85); roll = number (1, 85); skill_lev = ch->skills [skill]; skill_lev -= diff_mod; if ( ch->stun > 0 ) skill_lev -= ch->stun*2; if ( (af = get_affect (ch, MAGIC_AFFECT_CURSE)) ) skill_lev -= af->a.spell.modifier; for ( obj = ch->equip; obj; obj = obj->next_content ) { if ( GET_ITEM_TYPE (obj) == ITEM_WEAPON || GET_ITEM_TYPE (obj) == ITEM_SHIELD ) continue; for ( af = obj->xaffected; af; af = af->next ) { if ( af->a.spell.location - 10000 == skill ) skill_lev += af->a.spell.modifier; } } if ( (obj = ch->right_hand) ) { for ( af = obj->xaffected; af; af = af->next ) { if ( af->a.spell.location - 10000 == skill ) skill_lev += af->a.spell.modifier; } } if ( (obj = ch->left_hand) ) { for ( af = obj->xaffected; af; af = af->next ) { if ( af->a.spell.location - 10000 == skill ) skill_lev += af->a.spell.modifier; } } skill_lev = MAX (2, skill_lev); skill_lev = MIN (80, skill_lev); if ( !AWAKE(ch) ) return 0; if ( roll <= skill_lev ) return 1; if ( IS_NPC (ch) ) { if ( ch->skills [skill] < cap && lv >= number (1, 100) ) ch->skills [skill]++; } else if ( ch->pc->skills [skill] < cap && lv >= number (1, 100) ) { if ( !ch->desc || ch->desc->idle ) /* No skill gain idle/discon */ return 0; if ( IS_SET (ch->room->room_flags, OOC) ) /* No skill gain in OOC areas. */ return 0; if ( !get_affect (ch, MAGIC_SKILL_GAIN_STOP + skill) && !get_affect (ch, MAGIC_FLAG_NOGAIN + skill) ) { ch->skills [skill]++; ch->pc->skills [skill]++; min = 40; max = 40 + ch->skills [skill] + number(1,60); max = MIN (180, max); magic_add_affect (ch, MAGIC_SKILL_GAIN_STOP + skill, number(min,max), 0, 0, 0, 0); return 2; } } return 0; }