/* ************************************************************************ * file: limits.c , Limit and gain control module. Part of DIKUMUD * * Usage: Procedures controling gain and limit. * * Copyright (C) 1990, 1991 - see 'license.doc' for complete information. * ************************************************************************* */ #include <stdio.h> #include <assert.h> #include <string.h> #include <malloc.h> #include <stdlib.h> #include "structs.h" #include "limits.h" #include "utils.h" #include "spells.h" #include "comm.h" #include "db.h" char *titles[]={ "the Dog", "the Donkey", "the Cow", "the Pig", "the Chicken", "the Horse", "the Squirrel", "the Mouse", "the Goat", "the Turkey", "the Mole", "the Rat", "the Goose", "the Kangaroo", "the Snake" }; #define READ_TITLE(ch) titles[number(0,14)] extern struct char_data *character_list; extern struct obj_data *object_list; extern struct room_data *world; extern struct index_data *mob_index; /* External procedures */ void update_pos( struct char_data *victim ); /* in fight.c */ void damage(struct char_data *ch, struct char_data *victim, /* do */ int damage, int weapontype); struct time_info_data age(struct char_data *ch); int mana_limit(struct char_data *ch) { return(ch->points.max_mana + 1); } int hit_limit(struct char_data *ch) { return (ch->points.max_hit + 1); } int move_limit(struct char_data *ch) { return (ch->points.max_move + 1); } int mana_gain(struct char_data *ch) { int n,gain; if(IS_NPC(ch)) { /* Neat and fast */ gain = GET_LEVEL(ch); } else { gain = (GET_CON(ch)+GET_WIS(ch))/3; switch (GET_POS(ch)) { case POSITION_SLEEPING: gain += gain; if(GET_CON(ch) > 100) gain+=GET_CON(ch); if(IS_AFFECTED(ch,AFF_HYPERREGEN)) gain<<=1; break; case POSITION_RESTING: gain+= (gain>>1); /* Divide by 2 */ break; case POSITION_SITTING: gain += (gain>>2); /* Divide by 4 */ break; } if((GET_COND(ch,FULL)==0)||(GET_COND(ch,THIRST)==0)) gain >>= 2; else if((GET_COND(ch,DRUNK)) >= 8) gain <<= 1; if(IS_AFFECTED(ch,AFF_POISON)) gain = GET_MAX_MANA(ch)/(-336); } return (gain); } int hit_gain(struct char_data *ch) /* Hitpoint gain pr. game hour */ { int gain, n; if(IS_NPC(ch)) { gain = GET_LEVEL(ch); if(IS_AFFECTED(ch,AFF_REGEN)) gain <<= 2; } else { gain = (GET_STR(ch) + GET_CON(ch))/5; switch (GET_POS(ch)) { case POSITION_SLEEPING: gain += (gain>>1); if(GET_CON(ch) > 90) gain+=GET_CON(ch)-90; if(IS_AFFECTED(ch,AFF_HYPERREGEN)) gain<<=1; break; case POSITION_RESTING: gain+= (gain>>2); break; case POSITION_SITTING: gain += (gain>>3); break; } if((GET_COND(ch,FULL)==0)||(GET_COND(ch,THIRST)==0)) gain >>= 2; else if((GET_COND(ch,DRUNK)) >= 8) gain <<= 1; if(IS_AFFECTED(ch,AFF_POISON)) gain = GET_MAX_HIT(ch)/(-168); } if(IS_AFFECTED(ch,AFF_REGEN)) gain <<= 1; return (gain); } int move_gain(struct char_data *ch) { int gain; if(IS_NPC(ch)) { return(GET_LEVEL(ch)); } else { gain = (GET_DEX(ch) + GET_CON(ch))/2; switch (GET_POS(ch)) { case POSITION_SLEEPING: gain += (gain>>1); /* Divide by 2 */ break; case POSITION_RESTING: gain+= (gain>>2); /* Divide by 4 */ break; case POSITION_SITTING: gain += (gain>>3); /* Divide by 8 */ break; } } if (IS_AFFECTED(ch,AFF_POISON)) gain >>= 2; if((GET_COND(ch,FULL)==0)||(GET_COND(ch,THIRST)==0)) gain >>= 2; return (gain); } /* Gain maximum in various points */ void advance_level(struct char_data *ch) { int addx; addx = (GET_CON(ch)/8); addx += ((GET_LEVEL(ch) < 2) ? 2 : number(1,3)); ch->points.max_hit += MAX(1, addx); addx = (GET_INT(ch)/8); addx += ((GET_LEVEL(ch) < 2) ? 2 : number(1,3)); ch->points.max_mana += MAX(1, addx); addx = (GET_DEX(ch)/8); addx += 8; ch->points.max_move += MAX(1, addx); ch->specials.spells_to_learn += (9+GET_WIS(ch))/10; } void set_title(struct char_data *ch) { char *s; s=READ_TITLE(ch); if (GET_TITLE(ch)) RECREATE(GET_TITLE(ch),char,strlen(s)+1); else CREATE(GET_TITLE(ch),char,strlen(s)+1); strcpy(GET_TITLE(ch), s); } void gain_exp(struct char_data *ch, int gain) { int t, confactor; if(gain > 0){ /* SLUG_CHANGE 11-9-96 */ ch->specials.metadata[ch->specials.metadata[MAX_META_SAMPLES]] += gain; t=GET_EXP(ch); if((t > 0)&&((t+gain) < 0)){ send_to_char("Hey dogbreath, your experience is at the maximum!\n\r",ch); GET_EXP(ch) = 2147000000; return; } } if(IS_NPC(ch) || ((GET_LEVEL(ch)<IMO) && (GET_LEVEL(ch) > 0))) { if(gain > 0){ GET_EXP(ch) += gain; if(!IS_NPC(ch) && IS_SET(ch->specials.act,PLR_AUTOCNVRT)) if(GET_EXP(ch) >= 1000000){ GET_META(ch) += GET_EXP(ch)/1000000; GET_EXP(ch) %= 1000000; } } else if (gain < 0) { gain = abs(gain); if(GET_EXP(ch) > gain) GET_EXP(ch) -= gain; else GET_EXP(ch) = 0; } } } void gain_condition(struct char_data *ch,int condition,int value) { bool intoxicated; intoxicated=(GET_COND(ch, DRUNK) > 0); GET_COND(ch,condition) += value; GET_COND(ch,condition) = MAX(0,GET_COND(ch,condition)); GET_COND(ch,condition) = MIN(GET_GUT(ch),GET_COND(ch,condition)); if(GET_COND(ch,condition)) return; switch(condition){ case FULL : { send_to_char("You are hungry.\n\r",ch); return; } case THIRST : { send_to_char("You are thirsty.\n\r",ch); return; } case DRUNK : { if(intoxicated) send_to_char("You are now sober.\n\r",ch); return; } default : break; } } void check_idling(struct char_data *ch) { if (++(ch->specials.timer) > 8) if (ch->specials.was_in_room == NOWHERE && ch->in_room != NOWHERE) { ch->specials.was_in_room = ch->in_room; if (ch->specials.fighting) { stop_fighting(ch->specials.fighting); stop_fighting(ch); } act("$n disappears into the void.", TRUE, ch, 0, 0, TO_ROOM); send_to_char("You have been idle, and are pulled into a void.\n\r", ch); char_from_room(ch); char_to_room(ch, 1); /* Into room number 0 */ } else if (ch->specials.timer > 99) { if (ch->desc) close_socket(ch->desc); do_rent(ch,0,0); } } /* Update both PC's & NPC's and objects*/ void point_update( void ) { void update_char_objects( struct char_data *ch ); /* handler.c */ void extract_obj(struct obj_data *obj); /* handler.c */ struct char_data *i, *ni, *next_dude, *vict; struct obj_data *j, *next_thing, *jj, *next_thing2, *jjj; char *adp; int d1,d2,d3; int bdam,door,newroom; /* characters */ for (i = character_list; i; i = next_dude) { next_dude = i->next; if (GET_POS(i) > POSITION_STUNNED) { d1=hit_limit(i)-GET_HIT(i); if(d1 > 0){ d2=hit_gain(i); d3=MIN(d1,d2); GET_HIT(i) += d3; } d1=mana_limit(i)-GET_MANA(i); if(d1 > 0){ d2=mana_gain(i); d3=MIN(d1,d2); GET_MANA(i) += d3; GET_COND(i,FULL) = MAX(0,GET_COND(i,FULL)-d3/100); } d1=move_limit(i)-GET_MOVE(i); if(d1 > 0){ d2=move_gain(i); d3=MIN(d1,d2); GET_MOVE(i) += d3; GET_COND(i,THIRST) = MAX(0,GET_COND(i,THIRST)-d3/100); } } else if (GET_POS(i) == POSITION_STUNNED) { GET_HIT(i) = MIN(GET_HIT(i) + hit_gain(i), hit_limit(i)); GET_MANA(i) = MIN(GET_MANA(i) + mana_gain(i), mana_limit(i)); GET_MOVE(i) = MIN(GET_MOVE(i) + move_gain(i), move_limit(i)); } else if (GET_POS(i) == POSITION_INCAP) { damage(i, i, 1, TYPE_SUFFERING); } else if (!IS_NPC(i) && (GET_POS(i) == POSITION_MORTALLYW)) damage(i, i, 2, TYPE_SUFFERING); if (!IS_NPC(i)) { update_char_objects(i); if (GET_LEVEL(i) < (IMO+1)){ update_pos(i); check_idling(i); } } gain_condition(i,FULL,-1); gain_condition(i,DRUNK,-1); gain_condition(i,THIRST,-1); update_pos(i); if(GET_POS(i) == POSITION_DEAD) die(i); /* SLUG_CHANGE 11-9-96 Increment front of queue index */ i->specials.metadata[MAX_META_SAMPLES]++; i->specials.metadata[MAX_META_SAMPLES] %= MAX_META_SAMPLES; i->specials.metadata[i->specials.metadata[MAX_META_SAMPLES]] = 0; /* SLUG_CHANGE 11-13-96 increment char tic counter */ i->specials.connect_tics++; } /* for */ /* objects */ for(j = object_list; j ; j = next_thing){ next_thing = j->next; /* Next in object list */ if(IS_SET(j->obj_flags.extra_flags,ITEM_POOFSOON)){ if(j->obj_flags.timer) --j->obj_flags.timer; if(j->obj_flags.timer <= 0){ if(GET_ITEM_TYPE(j) == ITEM_BOMB) { if(i=j->carried_by){ act("A bomb in your inventory explodes, OUCH!!", FALSE,i,j,0,TO_CHAR); act("A bomb carried by $n EXPLODES, causing bodily harm!!", FALSE,i,j,0,TO_NOTVICT); if(!IS_SET(world[i->in_room].room_flags,LAWFUL)) if(IS_NPC(i) || (GET_LEVEL(i) < IMO)){ GET_HIT(i) -= MIN(j->obj_flags.value[0],GET_HIT(i)-1); update_pos(i); } extract_obj(j); } else if (j->in_room != NOWHERE) { if(!IS_SET(world[j->in_room].room_flags,LAWFUL)){ for(i=world[j->in_room].people;i;i=ni){ ni=i->next_in_room; if(IS_NPC(i)){ if(IS_SET(i->specials.act,ACT_SMART)){ if(GET_POS(i) < POSITION_STANDING) do_stand(i,0,0); if(j->obj_flags.value[0] > (GET_HIT(i)>>4)){ if(number(0,4)) defuser(i,0,0); else do_flee(i,0,0); } } } } for(i=world[j->in_room].people;i;i=ni){ ni=i->next_in_room; if(IS_NPC(i) || (GET_LEVEL(i) < IMO)){ if(!IS_NPC(i)) send_to_char("You are hurt!\n\r",i); bdam = MIN((j->obj_flags.value[0])>>1,GET_HIT(i)-1); if((jjj=i->equipment[WEAR_SHIELD])&& (jjj->obj_flags.value[1]==SHIELD_BOMB)) bdam>>=2; GET_HIT(i) -= bdam; update_pos(i); } } send_to_room("An explosion rocks the room!\n\r",j->in_room); for(door=0;door<=5;door++) if((world[j->in_room].dir_option[door])&& ((newroom=world[j->in_room].dir_option[door]->to_room) > 0)) send_to_room("You hear a nearby explosion.\n\r",newroom); } else { send_to_room("Your hear a loud POP!\n\r",j->in_room); } extract_obj(j); } } else if (j->carried_by){ act("It seems that $p has vanished!", FALSE,j->carried_by,j,0,TO_CHAR); extract_obj(j); } else if ((j->in_room != NOWHERE) && (world[j->in_room].people)){ act("Miraculously, $p vanishes.", TRUE, world[j->in_room].people, j, 0, TO_ROOM); extract_obj(j); } } } else if((GET_ITEM_TYPE(j)==ITEM_CONTAINER)&&(j->obj_flags.value[3])){ /* timer count down */ if (j->obj_flags.timer > 0) j->obj_flags.timer--; if (!j->obj_flags.timer) { if (j->carried_by) act("The $p decays in your hands.",FALSE,j->carried_by,j,0,TO_CHAR); else if ((j->in_room != NOWHERE) && (world[j->in_room].people)){ act("The $p dries up and blows away.", TRUE, world[j->in_room].people, j, 0, TO_ROOM); act("The $p dries up and blows away.", TRUE, world[j->in_room].people, j, 0, TO_CHAR); } for(jj = j->contains; jj; jj = next_thing2) { next_thing2 = jj->next_content; /* Next in inventory */ obj_from_obj(jj); if (j->in_obj) obj_to_obj(jj,j->in_obj); else if (j->carried_by) obj_to_char(jj,j->carried_by); else if (j->in_room != NOWHERE) obj_to_room(jj,j->in_room); else assert(FALSE); } extract_obj(j); } } } } void recover_in_rent(struct char_data *ch) { int t,dhp,dma,dmo; char buf[256]; t=(ch->specials.xxx)/15; ch->specials.xxx=0; sprintf(buf,"You were gone %d ticks.\n\r",t); send_to_char(buf,ch); if(t < 120) return; t<<=2; dhp = hit_gain(ch); if(dhp < 0) dhp=0; dma = mana_gain(ch); if(dma < 0) dma=0; dmo = move_gain(ch); if(dmo < 0) dmo=0; GET_HIT(ch) = MIN(GET_HIT(ch) + t*dhp, hit_limit(ch)); GET_MANA(ch) = MIN(GET_MANA(ch) + t*dma, mana_limit(ch)); GET_MOVE(ch) = MIN(GET_MOVE(ch) + t*dmo, move_limit(ch)); send_to_char("You feel refreshed from your long nap.\n\r",ch); }