/* SillyMUD Distribution V1.1b (c) 1993 SillyMUD Developement See license.doc for distribution terms. SillyMUD is based on DIKUMUD */ #include <stdio.h> #include "protos.h" extern char *dirs[]; extern struct char_data *character_list; extern struct str_app_type str_app[]; extern struct room_data *world; extern struct dex_app_type dex_app[]; extern struct skill_data skill_info[]; extern struct index_data *obj_index; struct hunting_data { char *name; struct char_data **victim; }; /*************************************/ /* predicates for find_path function */ int is_target_room_p(int room, void *tgt_room); int named_object_on_ground(int room, void *c_data); /* predicates for find_path function */ /*************************************/ /* ** train: */ void do_train(struct char_data *ch, char *argument, int cmd) { /* code to allow high level characters to train low level characters. */ } void do_inset(struct char_data *ch, char *argument, int cmd) { /* code which allows a character to inset a stone into a weapon. The stone's powers are added to the weapon */ struct obj_data *sword, *gem, *tmp; struct char_data *tmp_char; /* dummy */ char sp[100], sp2[100], buf[512]; int ok=FALSE; struct extra_descr_data *new_descr; int stone_slots, sword_slots, i, j, bits, perc; /* get the sword and the gem from the argument */ if (!ch->skills) return; argument_interpreter(argument, sp, sp2); if (!(*sp) || !(*sp2)) { send_to_char("You must supply a weapon and a treasure.\n\r", ch); return; } bits = generic_find(sp, FIND_OBJ_INV, ch, &tmp_char, &sword); bits = generic_find(sp2, FIND_OBJ_INV, ch, &tmp_char, &gem); /* make sure we have a gem and a sword */ if (!sword) { send_to_char("Inset what?\n\r", ch); return; } if (!gem) { send_to_char("Inset what?\n\r", ch); return; } if ((ITEM_TYPE(sword) == ITEM_WEAPON) && (ITEM_TYPE(gem) == ITEM_TREASURE)) { ok = TRUE; } else if ((ITEM_TYPE(gem) == ITEM_WEAPON) && (ITEM_TYPE(sword) == ITEM_TREASURE)) { tmp = gem; gem = sword; sword = tmp; ok = TRUE; } if (!ok) { /* I can't beleive you fucked the act */ /* parameters. */ if (GET_ITEM_TYPE(sword) != ITEM_WEAPON) { act("$p is not a weapon.", 0, ch, sword, sword, TO_CHAR); } if (GET_ITEM_TYPE(gem) != ITEM_TREASURE) { act("$p is not a gem.", 0, ch, gem, gem, TO_CHAR); } return; } if (sword->obj_flags.weight < gem->obj_flags.weight) { send_to_char("That weapon is too small for such a treasure.\n\r",ch); /* act("That weapon is too small for such a treasure", 0, ch, 0, 0, TO_CHAR); */ return; } /* count the effects on the stone */ for (i=0, stone_slots=0; i < MAX_OBJ_AFFECT; i++) { if (gem->affected[i].location != APPLY_NONE) stone_slots++; } /* count the effects on the sword */ for (i=0, sword_slots=0; i < MAX_OBJ_AFFECT; i++) { if (sword->affected[i].location == APPLY_NONE) sword_slots++; } /* verify space is available */ if (stone_slots > sword_slots) { act("$p can't hold that many enchantments", 0, ch, sword, sword, TO_CHAR); return; } if (IS_OBJ_STAT(sword, ITEM_INSET)) { act("$p has already been inset with a gem", 0, ch, sword, sword, TO_CHAR); return; } /* check skill role. Failure damages the stone and weapon */ perc = number(1,101); if (perc > ch->skills[SKILL_INSET].learned) { act("$n fumbles with $p and breaks it!", 0, ch, gem, gem, TO_ROOM); act("You fumble with $p and break it!", 0, ch, gem, gem, TO_CHAR); MakeScrap(ch, gem); return; } /* if success, add stone's effects to sword */ act("$n insets $p into $P", 0, ch, gem , sword, TO_ROOM); act("You inset $p into $P", 0, ch, gem , sword, TO_CHAR); SET_BIT(sword->obj_flags.extra_flags, ITEM_INSET); /* add an extra description for the stone to the object*/ CREATE(new_descr, struct extra_descr_data, 1); sprintf(buf, "%s hilt",sword->name); new_descr->keyword = strdup(buf); sprintf(buf, "It is inset with %s", gem->short_description); new_descr->description = strdup(buf); new_descr->next = sword->ex_description; sword->ex_description = new_descr; for (i=0; i < MAX_OBJ_AFFECT; i++) { if (gem->affected[i].location != APPLY_NONE) { j = getFreeAffSlot(sword); sword->affected[j].location = gem->affected[i].location; sword->affected[j].modifier = gem->affected[i].modifier; } } /* add stone's value to sword's rent (ego) */ GET_RENT(sword) += GET_VALUE(gem); /* delete stone */ obj_from_char(gem); extract_obj(gem); } /* ** Disarm: */ void do_disarm(struct char_data *ch, char *argument, int cmd) { char name[30]; int percent; struct char_data *victim; struct obj_data *w, *trap; if (!ch->skills) return; if (check_peaceful(ch,"You feel too peaceful to contemplate violence.\n\r")) return; if (!IS_PC(ch) && cmd) return; /* * get victim */ only_argument(argument, name); if (!(victim = get_char_room_vis(ch, name))) { if (ch->specials.fighting) { victim = ch->specials.fighting; } else { if (!ch->skills[SKILL_REMOVE_TRAP].learned) { send_to_char("Disarm who?\n\r", ch); return; } else { if (MOUNTED(ch)) { send_to_char("Yeah... right... while mounted\n\r", ch); return; } if (!(trap = get_obj_in_list_vis(ch, name, real_roomp(ch->in_room)->contents))) { if (!(trap = get_obj_in_list_vis(ch, name, ch->carrying))) { send_to_char("Disarm what?\n\r", ch); return; } } if (trap) { remove_trap(ch, trap); return; } } } } if (victim == ch) { send_to_char("Aren't we funny today...\n\r", ch); return; } if (victim != ch->specials.fighting) { send_to_char("but you aren't fighting them!\n\r", ch); return; } if (ch->attackers > 3) { send_to_char("There is no room to disarm!\n\r", ch); return; } if (!HasClass(ch, CLASS_WARRIOR) && !HasClass(ch, CLASS_MONK)) { send_to_char("You're no warrior!\n\r", ch); return; } /* * make roll - modified by dex && level */ percent=number(1,101); /* 101% is a complete failure */ percent -= dex_app[GET_DEX(ch)].reaction*10; percent += dex_app[GET_DEX(victim)].reaction*10; if (!ch->equipment[WIELD] && !HasClass(ch, CLASS_MONK)) { percent += 50; } percent += GetMaxLevel(victim); if (HasClass(victim, CLASS_MONK)) percent += GetMaxLevel(victim); if (HasClass(ch, CLASS_MONK)) { percent -= GetMaxLevel(ch); } else { percent -= GetMaxLevel(ch)>>1; } if (percent > ch->skills[SKILL_DISARM].learned) { /* * failure. */ act("You try to disarm $N, but fail miserably.", TRUE, ch, 0, victim, TO_CHAR); act("$n does a nifty fighting move, but then falls on $s butt.", TRUE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POSITION_SITTING; if ((IS_NPC(victim)) && (GET_POS(victim) > POSITION_SLEEPING) && (!victim->specials.fighting)) { set_fighting(victim, ch); } LearnFromMistake(ch, SKILL_DISARM, 0, 95); WAIT_STATE(ch, PULSE_VIOLENCE*3); } else { /* * success */ if (victim->equipment[WIELD]) { w = unequip_char(victim, WIELD); act("$n makes an impressive fighting move.", TRUE, ch, 0, 0, TO_ROOM); act("You send $p flying from $N's grasp.", TRUE, ch, w, victim, TO_CHAR); act("$p flies from your grasp.", TRUE, ch, w, victim, TO_VICT); /* send the object to a nearby room, instead */ obj_to_room(w, victim->in_room); } else { act("You try to disarm $N, but $E doesn't have a weapon.", TRUE, ch, 0, victim, TO_CHAR); act("$n makes an impressive fighting move, but does little more.", TRUE, ch, 0, 0, TO_ROOM); } if ((IS_NPC(victim)) && (GET_POS(victim) > POSITION_SLEEPING) && (!victim->specials.fighting)) { set_fighting(victim, ch); } WAIT_STATE(victim, PULSE_VIOLENCE*2); WAIT_STATE(ch, PULSE_VIOLENCE*2); } } /* ** Track: */ int named_mobile_in_room(int room, struct hunting_data *c_data) { struct char_data *scan; for (scan = real_roomp(room)->people; scan; scan = scan->next_in_room) if (isname(c_data->name, scan->player.name)) { *(c_data->victim) = scan; return 1; } return 0; } void do_track(struct char_data *ch, char *argument, int cmd) { char name[256], buf[256], found=FALSE; int dist, code; struct hunting_data huntd; struct char_data *scan; extern struct char_data *character_list; #if NOTRACK send_to_char("Sorry, tracking is disabled. Try again after reboot.\n\r",ch); return; #endif only_argument(argument, name); found = FALSE; for (scan = character_list; scan && !found ; scan = scan->next) if (isname(name, scan->player.name)) { found = TRUE; } if (!found) { send_to_char("You are unable to find traces of one.\n\r", ch); return; } if (!ch->skills) dist = 10; else dist = ch->skills[SKILL_HUNT].learned; if (IS_SET(ch->player.class, CLASS_THIEF)) { dist *= 3; } switch(GET_RACE(ch)){ case RACE_ELVEN: dist *= 2; /* even better */ break; case RACE_DEVIL: case RACE_DEMON: dist = MAX_ROOMS; /* as good as can be */ break; default: break; } if (GetMaxLevel(ch) >= IMMORTAL) dist = MAX_ROOMS; if (affected_by_spell(ch, SPELL_MINOR_TRACK)) { dist = GetMaxLevel(ch) * 10; } else if (affected_by_spell(ch, SPELL_MAJOR_TRACK)){ dist = GetMaxLevel(ch) * 20; } if (dist == 0) return; ch->hunt_dist = dist; ch->specials.hunting = 0; huntd.name = name; huntd.victim = &ch->specials.hunting; if ((GetMaxLevel(ch) < MIN_GLOB_TRACK_LEV) || (affected_by_spell(ch, SPELL_MINOR_TRACK)) || (affected_by_spell(ch, SPELL_MAJOR_TRACK))) { code = find_path( ch->in_room, named_mobile_in_room, &huntd, -dist, 1); } else { code = find_path( ch->in_room, named_mobile_in_room, &huntd, -dist, 0); } WAIT_STATE(ch, PULSE_VIOLENCE*1); if(ch->specials.hunting) { if(GET_RACE(ch->specials.hunting) == RACE_VEGMAN && real_roomp(ch->specials.hunting->in_room)->sector_type != SECT_FOREST) { send_to_char("You are unable to find traces of one.\n\r", ch); ch->specials.hunting = 0; return; } if(IS_SET(ch->specials.act, ACT_SENTINEL) || IS_AFFECTED(ch->specials.hunting, AFF_FLYING)) { send_to_char("You are unable to find traces of one.\n\r", ch); ch->specials.hunting = 0; return; } } if (code == -1) { send_to_char("You are unable to find traces of one.\n\r", ch); return; } else if (code == -69) { send_to_char("Look in front of your nose, dolt!\n\r",ch); return; } else { if (IS_LIGHT(ch->in_room) || IS_AFFECTED(ch, AFF_TRUE_SIGHT) ) { SET_BIT(ch->specials.act, PLR_HUNTING); sprintf(buf, "You see traces of your quarry to the %s.\n\r", dirs[code]); send_to_char(buf,ch); } else { ch->specials.hunting = 0; send_to_char("It's too dark in here to track...\n\r",ch); return; } } } int track( struct char_data *ch, struct char_data *vict) { char buf[256]; int code; if ((!ch) || (!vict)) return(-1); if ((GetMaxLevel(ch) < MIN_GLOB_TRACK_LEV) || (affected_by_spell(ch, SPELL_MINOR_TRACK)) || (affected_by_spell(ch, SPELL_MAJOR_TRACK))) { code = choose_exit_in_zone(ch->in_room, vict->in_room, ch->hunt_dist); } else { code = choose_exit_global(ch->in_room, vict->in_room, ch->hunt_dist); } if ((!ch) || (!vict)) return(-1); if (ch->in_room == vict->in_room) { send_to_char("##You have found your target!\n\r",ch); return(FALSE); /* false to continue the hunt */ } if (code == -1) { send_to_char("##You have lost the trail.\n\r",ch); return(FALSE); } else { sprintf(buf, "##You see a faint trail to the %s.\n\r", dirs[code]); send_to_char(buf, ch); return(TRUE); } } int dir_track( struct char_data *ch, struct char_data *vict) { char buf[256]; int code; if ((!ch) || (!vict)) return(-1); if ((GetMaxLevel(ch) >= MIN_GLOB_TRACK_LEV) || (affected_by_spell(ch, SPELL_MINOR_TRACK)) || (affected_by_spell(ch, SPELL_MAJOR_TRACK))) { code = choose_exit_global(ch->in_room, vict->in_room, ch->hunt_dist); } else { code = choose_exit_in_zone(ch->in_room, vict->in_room, ch->hunt_dist); } if ((!ch) || (!vict)) return(-1); if (code == -1) { if (ch->in_room == vict->in_room) { send_to_char("##You have found your target!\n\r",ch); } else { send_to_char("##You have lost the trail.\n\r",ch); } return(-1); /* false to continue the hunt */ } else { sprintf(buf, "##You see a faint trail to the %s.\n\r", dirs[code]); send_to_char(buf, ch); return(code); } } /** Perform breadth first search on rooms from start (in_room) **/ /** until end (tgt_room) is reached. Then return the correct **/ /** direction to take from start to reach end. **/ /* thoth@manatee.cis.ufl.edu if dvar<0 then search THROUGH closed but not locked doors, for mobiles that know how to open doors. */ #define IS_DIR (real_roomp(q_head->room_nr)->dir_option[i]) #define GO_OK (!IS_SET(IS_DIR->exit_info,EX_CLOSED)\ && (IS_DIR->to_room != NOWHERE)) #define GO_OK_SMARTER (!IS_SET(IS_DIR->exit_info,EX_LOCKED)\ && (IS_DIR->to_room != NOWHERE)) void donothing() { return; } int find_path(int in_room, int (*predicate)(), void *c_data, int depth, int in_zone) { struct room_q *tmp_q, *q_head, *q_tail; #if 1 struct hash_header x_room; /* static struct hash_header x_room; */ #else struct nodes x_room[MAX_ROOMS]; #endif int i, tmp_room, count=0, thru_doors; struct room_data *herep, *therep; struct room_data *startp; struct room_direction_data *exitp; /* If start = destination we are done */ if ((predicate)(in_room, c_data)) return(-69); /* <grin> couldn't return a direction */ #if 0 if (top_of_world > MAX_ROOMS) { log("TRACK Is disabled, too many rooms.\n\rContact Loki soon.\n\r"); return -1; } #endif if (depth<0) { thru_doors = TRUE; depth = - depth; } else { thru_doors = FALSE; } startp = real_roomp(in_room); init_hash_table(&x_room, sizeof(int), 2048); hash_enter(&x_room, in_room, (void*)-1); /* initialize queue */ q_head = (struct room_q *) malloc(sizeof(struct room_q)); q_tail = q_head; q_tail->room_nr = in_room; q_tail->next_q = 0; while(q_head) { herep = real_roomp(q_head->room_nr); /* for each room test all directions */ if (herep->zone == startp->zone || !in_zone) { /* only look in this zone.. saves cpu time. makes world safer for players */ for(i = 0; i <= 5; i++) { exitp = herep->dir_option[i]; if (exit_ok(exitp, &therep) && (thru_doors ? GO_OK_SMARTER : GO_OK)) { /* next room */ tmp_room = herep->dir_option[i]->to_room; if(!((predicate)(tmp_room, c_data))) { /* shall we add room to queue ? */ /* count determines total breadth and depth */ if(!hash_find(&x_room,tmp_room) && (count < depth) && !IS_SET(RM_FLAGS(tmp_room),DEATH)) { count++; /* mark room as visted and put on queue */ tmp_q = (struct room_q *) malloc(sizeof(struct room_q)); tmp_q->room_nr = tmp_room; tmp_q->next_q = 0; q_tail->next_q = tmp_q; q_tail = tmp_q; /* ancestor for first layer is the direction */ hash_enter(&x_room, tmp_room, ((int)hash_find(&x_room,q_head->room_nr) == -1) ? (void*)(i+1) : hash_find(&x_room,q_head->room_nr)); } } else { /* have reached our goal so free queue */ tmp_room = q_head->room_nr; for(;q_head;q_head = tmp_q) { tmp_q = q_head->next_q; free(q_head); } /* return direction if first layer */ if ((int)hash_find(&x_room,tmp_room)==-1) { if (x_room.buckets) { /* junk left over from a previous track */ destroy_hash_table(&x_room, donothing); } return(i); } else { /* else return the ancestor */ int i; i = (int)hash_find(&x_room,tmp_room); if (x_room.buckets) { /* junk left over from a previous track */ destroy_hash_table(&x_room, donothing); } return( -1+i); } } } } } /* free queue head and point to next entry */ tmp_q = q_head->next_q; free(q_head); q_head = tmp_q; } /* couldn't find path */ if (x_room.buckets) { /* junk left over from a previous track */ destroy_hash_table(&x_room, donothing); } return(-1); } int choose_exit_global(int in_room, int tgt_room, int depth) { return find_path(in_room, is_target_room_p, (void*)tgt_room, depth, 0); } int choose_exit_in_zone(int in_room, int tgt_room, int depth) { return find_path(in_room, is_target_room_p, (void*)tgt_room, depth, 1); } int go_direction(struct char_data *ch, int dir) { if (ch->specials.fighting) return 0; if (!IS_SET(EXIT(ch,dir)->exit_info, EX_CLOSED)) { do_move(ch, "", dir+1); } else if ( IsHumanoid(ch) && !IS_SET(EXIT(ch,dir)->exit_info, EX_LOCKED) ) { open_door(ch, dir); return 0; } } void slam_into_wall( struct char_data *ch, struct room_direction_data *exitp) { char doorname[128]; char buf[256]; if (exitp->keyword && *exitp->keyword) { if ((strcmp(fname(exitp->keyword), "secret")==0) || (IS_SET(exitp->exit_info, EX_SECRET))) { strcpy(doorname, "wall"); } else { strcpy(doorname, fname(exitp->keyword)); } } else { strcpy(doorname, "barrier"); } sprintf(buf, "You slam against the %s with no effect.\n\r", doorname); send_to_char(buf, ch); send_to_char("OUCH! That REALLY Hurt!\n\r", ch); sprintf(buf, "$n crashes against the %s with no effect.\n\r", doorname); act(buf, FALSE, ch, 0, 0, TO_ROOM); GET_HIT(ch) -= number(1, 10)*2; if (GET_HIT(ch) < 0) GET_HIT(ch) = 0; GET_POS(ch) = POSITION_STUNNED; return; } /* skill to allow fighters to break down doors */ void do_doorbash( struct char_data *ch, char *arg, int cmd) { extern char *dirs[]; int dir; int ok; struct room_direction_data *exitp; int was_in, roll; char buf[256], type[128], direction[128]; if (GET_MOVE(ch) < 10) { send_to_char("You're too tired to do that\n\r", ch); return; } if (MOUNTED(ch)) { send_to_char("Yeah... right... while mounted\n\r", ch); return; } /* make sure that the argument is a direction, or a keyword. */ for (;*arg == ' '; arg++); argument_interpreter(arg, type, direction); if ((dir = find_door(ch, type, direction)) >= 0) { ok = TRUE; } else { act("$n looks around, bewildered.", FALSE, ch, 0, 0, TO_ROOM); return; } if (!ok) { send_to_char("Hmm, you shouldn't have gotten this far\n\r", ch); return; } exitp = EXIT(ch, dir); if (!exitp) { send_to_char("you shouldn't have gotten here.\n\r", ch); return; } if (dir == UP) { if (real_roomp(exitp->to_room)->sector_type == SECT_AIR && !IS_AFFECTED(ch, AFF_FLYING)) { send_to_char("You have no way of getting there!\n\r", ch); return; } } sprintf(buf, "$n charges %swards", dirs[dir]); act(buf, FALSE, ch, 0, 0, TO_ROOM); sprintf(buf, "You charge %swards\n\r", dirs[dir]); send_to_char(buf, ch); if (!IS_SET(exitp->exit_info, EX_CLOSED)) { was_in = ch->in_room; char_from_room(ch); char_to_room(ch, exitp->to_room); do_look(ch, "", 0); DisplayMove(ch, dir, was_in, 1); if (!check_falling(ch)) { if (IS_SET(RM_FLAGS(ch->in_room), DEATH) && GetMaxLevel(ch) < LOW_IMMORTAL) { NailThisSucker(ch); return; } else { WAIT_STATE(ch, PULSE_VIOLENCE*3); GET_MOVE(ch) -= 10; } } else { return; } WAIT_STATE(ch, PULSE_VIOLENCE*3); GET_MOVE(ch) -= 10; return; } GET_MOVE(ch) -= 10; if (IS_SET(exitp->exit_info, EX_LOCKED) && IS_SET(exitp->exit_info, EX_PICKPROOF)) { slam_into_wall(ch, exitp); return; } /* now we've checked for failures, time to check for success; */ if (ch->skills) { if (ch->skills[SKILL_DOORBASH].learned) { roll = number(1, 100); if (roll > ch->skills[SKILL_DOORBASH].learned) { slam_into_wall(ch, exitp); LearnFromMistake(ch, SKILL_DOORBASH, 0, 95); } else { /* unlock and open the door */ sprintf(buf, "$n slams into the %s, and it bursts open!", fname(exitp->keyword)); act(buf, FALSE, ch, 0, 0, TO_ROOM); sprintf(buf, "You slam into the %s, and it bursts open!\n\r", fname(exitp->keyword)); send_to_char(buf, ch); raw_unlock_door(ch, exitp, dir); raw_open_door(ch, dir); GET_HIT(ch) -= number(1,5); /* Now a dex check to keep from flying into the next room */ roll = number(1, 20); if (roll > GET_DEX(ch)) { was_in = ch->in_room; char_from_room(ch); char_to_room(ch, exitp->to_room); do_look(ch, "", 0); DisplayMove(ch, dir, was_in, 1); if (!check_falling(ch)) { if (IS_SET(RM_FLAGS(ch->in_room), DEATH) && GetMaxLevel(ch) < LOW_IMMORTAL) { NailThisSucker(ch); return; } } else { return; } WAIT_STATE(ch, PULSE_VIOLENCE*3); GET_MOVE(ch) -= 10; return; } else { WAIT_STATE(ch, PULSE_VIOLENCE*1); GET_MOVE(ch) -= 5; return; } } } else { send_to_char("You just don't know the nuances of door-bashing.\n\r", ch); slam_into_wall(ch, exitp); return; } } else { send_to_char("You're just a goofy mob.\n\r", ch); return; } } /* skill to allow anyone to move through rivers and underwater */ void do_swim( struct char_data *ch, char *arg, int cmd) { struct affected_type af; byte percent; send_to_char("Ok, you'll try to swim for a while.\n\r", ch); if (IS_AFFECTED(ch, AFF_WATERBREATH)) { /* kinda pointless if they don't need to...*/ return; } if (affected_by_spell(ch, SKILL_SWIM)) { send_to_char("You're too exhausted to swim right now\n", ch); return; } percent=number(1,101); /* 101% is a complete failure */ if (!ch->skills) return; if (percent > ch->skills[SKILL_SWIM].learned) { send_to_char("You're too afraid to enter the water.\n\r",ch); if (ch->skills[SKILL_SWIM].learned < 95 && ch->skills[SKILL_SWIM].learned > 0) { if (number(1,101) > ch->skills[SKILL_SWIM].learned) { send_to_char("You feel a bit braver, though.\n\r", ch); ch->skills[SKILL_SWIM].learned++; } } return; } af.type = SKILL_SWIM; af.duration = (ch->skills[SKILL_SWIM].learned/10)+1; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_WATERBREATH; affect_to_char(ch, &af); af.type = SKILL_SWIM; af.duration = 13; af.modifier = -10; af.location = APPLY_MOVE; af.bitvector = 0; affect_to_char(ch, &af); } int SpyCheck(struct char_data *ch) { if (!ch->skills) return(FALSE); if (number(1,101) > ch->skills[SKILL_SPY].learned) return(FALSE); return(TRUE); } void do_spy( struct char_data *ch, char *arg, int cmd) { struct affected_type af; send_to_char("Ok, you'll try to act like a secret agent.\n\r", ch); if (IS_AFFECTED(ch, AFF_SCRYING)) { return; } if (affected_by_spell(ch, SKILL_SPY)) { send_to_char("You're already acting like a secret agent.\n", ch); return; } if (!ch->skills) return; if (number(1,101) > ch->skills[SKILL_SPY].learned) { LearnFromMistake(ch, SKILL_SPY, 0, 95); af.type = SKILL_SPY; af.duration = (ch->skills[SKILL_SPY].learned/10)+1; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = 0; affect_to_char(ch, &af); return; } af.type = SKILL_SPY; af.duration = (ch->skills[SKILL_SPY].learned/10)+1; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = AFF_SCRYING; affect_to_char(ch, &af); return; } int remove_trap( struct char_data *ch, struct obj_data *trap) { int num; if (ITEM_TYPE(trap) != ITEM_TRAP) { send_to_char("That's no trap!\n\r", ch); return(FALSE); } if (GET_TRAP_CHARGES(trap) <= 0) { send_to_char("That trap is already sprung!\n\r", ch); return(FALSE); } num = number(1,101); if (num < ch->skills[SKILL_REMOVE_TRAP].learned) { send_to_char("<Click>\n\r", ch); act("$n disarms $p", FALSE, ch, trap, 0, TO_ROOM); GET_TRAP_CHARGES(trap) = 0; return(TRUE); } else { send_to_char("<Click>\n\r(uh oh)\n\r", ch); act("$n attempts to disarm $p, ack!", FALSE, ch, trap, 0, TO_ROOM); TriggerTrap(ch, trap); return(TRUE); } } void do_feign_death( struct char_data *ch, char *arg, int cmd) { struct room_data *rp; struct char_data *t; if (!ch->skills) return; if (!ch->specials.fighting) { send_to_char("But you are not fighting anything...\n\r", ch); return; } if (!HasClass(ch, CLASS_MONK)) { send_to_char("You're no monk!\n\r", ch); return; } if (MOUNTED(ch)) { send_to_char("Yeah... right... while mounted\n\r", ch); return; } rp = real_roomp(ch->in_room); if (!rp) return; send_to_char("You try to fake your own demise\n\r", ch); death_cry(ch); act("$n is dead! R.I.P.", FALSE, ch, 0, 0, TO_ROOM); if (number(1,101) < ch->skills[SKILL_FEIGN_DEATH].learned) { stop_fighting(ch); for (t = rp->people;t;t=t->next_in_room) { if (t->specials.fighting == ch) { stop_fighting(t); if (number(1,101) < ch->skills[SKILL_FEIGN_DEATH].learned/2) SET_BIT(ch->specials.affected_by, AFF_HIDE); GET_POS(ch) = POSITION_SLEEPING; } } WAIT_STATE(ch, PULSE_VIOLENCE*2); return; } else { GET_POS(ch) = POSITION_SLEEPING; WAIT_STATE(ch, PULSE_VIOLENCE*3); LearnFromMistake(ch, SKILL_FEIGN_DEATH, 0, 95); } } void do_first_aid( struct char_data *ch, char *arg, int cmd) { struct affected_type af; send_to_char("You attempt to render first aid unto yourself.\n\r", ch); if (affected_by_spell(ch, SKILL_FIRST_AID)) { send_to_char("You can only do this once per day.\n\r", ch); return; } if (number(1,101) < ch->skills[SKILL_FIRST_AID].learned) { GET_HIT(ch)+= number(1,20) + (GetMaxLevel(ch)/2); if(GET_HIT(ch) > GET_MAX_HIT(ch)) GET_HIT(ch) = GET_MAX_HIT(ch); af.duration = 24; } else { af.duration = 6; LearnFromMistake(ch, SKILL_FEIGN_DEATH, TRUE, 95); } af.type = SKILL_FIRST_AID; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = 0; affect_to_char(ch, &af); return; } void do_disguise(struct char_data *ch, char *argument, int cmd) { struct affected_type af; send_to_char("You attempt to disguise yourself\n\r", ch); if (affected_by_spell(ch, SKILL_DISGUISE)) { send_to_char("You can only do this once per day\n\r", ch); return; } if (number(1,101) < ch->skills[SKILL_DISGUISE].learned) { struct char_data *k; for (k=character_list; k; k=k->next) { if (k->specials.hunting == ch) { k->specials.hunting = 0; } if (number(1,101) < ch->skills[SKILL_DISGUISE].learned) { if (Hates(k, ch)) { ZeroHatred(k, ch); } if (Fears(k, ch)) { ZeroFeared(k, ch); } } } } else { LearnFromMistake(ch, SKILL_DISGUISE, 0, 95); } af.type = SKILL_DISGUISE; af.duration = 24; af.modifier = 0; af.location = APPLY_NONE; af.bitvector = 0; affect_to_char(ch, &af); return; } /* Skill for climbing walls and the like -DM */ void do_climb( struct char_data *ch, char *arg, int cmd) { extern char *dirs[]; int dir; struct room_direction_data *exitp; int was_in, roll; extern char *dirs[]; char buf[256], type[128], direction[128]; if (GET_MOVE(ch) < 10) { send_to_char("You're too tired to do that\n\r", ch); return; } if (MOUNTED(ch)) { send_to_char("Yeah... right... while mounted\n\r", ch); return; } /* make sure that the argument is a direction, or a keyword. */ for (;*arg == ' '; arg++); only_argument(arg,direction); if ((dir = search_block(direction, dirs, FALSE)) < 0) { send_to_char("You can't climb that way.\n\r", ch); return; } exitp = EXIT(ch, dir); if (!exitp) { send_to_char("You can't climb that way.\n\r", ch); return; } if(!IS_SET(exitp->exit_info, EX_CLIMB)) { send_to_char("You can't climb that way.\n\r", ch); return; } if (dir == UP) { if (real_roomp(exitp->to_room)->sector_type == SECT_AIR && !IS_AFFECTED(ch, AFF_FLYING)) { send_to_char("You have no way of getting there!\n\r", ch); return; } } if (IS_SET(exitp->exit_info, EX_ISDOOR) && IS_SET(exitp->exit_info, EX_CLOSED)) { send_to_char("You can't climb that way.\n\r", ch); return; } sprintf(buf, "$n attempts to climb %swards", dirs[dir]); act(buf, FALSE, ch, 0, 0, TO_ROOM); sprintf(buf, "You attempt to climb %swards\n\r", dirs[dir]); send_to_char(buf, ch); GET_MOVE(ch) -= 10; /* now we've checked for failures, time to check for success; */ if (ch->skills) { if (ch->skills[SKILL_CLIMB].learned) { roll = number(1, 100); if (roll > ch->skills[SKILL_CLIMB].learned) { slip_in_climb(ch, dir, exitp->to_room); LearnFromMistake(ch, SKILL_CLIMB, 0, 95); } else { was_in = ch->in_room; char_from_room(ch); char_to_room(ch, exitp->to_room); do_look(ch, "", 0); DisplayMove(ch, dir, was_in, 1); if (!check_falling(ch)) { if (IS_SET(RM_FLAGS(ch->in_room), DEATH) && GetMaxLevel(ch) < LOW_IMMORTAL) { NailThisSucker(ch); return; } } WAIT_STATE(ch, PULSE_VIOLENCE*3); GET_MOVE(ch) -= 10; return; } } else { send_to_char("You just don't know the nuances of climbing.\n\r", ch); slip_in_climb(ch, dir, exitp->to_room); return; } } else { send_to_char("You're just a goofy mob.\n\r", ch); return; } } void slip_in_climb(struct char_data *ch, int dir, int room) { int i; i = number(1, 6); if(dir != DOWN) { act("$n falls down and goes splut.", FALSE, ch, 0, 0, TO_ROOM); send_to_char("You fall.\n\r", ch); } else { act("$n loses $s grip and falls further down.", FALSE, ch, 0, 0, TO_ROOM); send_to_char("You slip and start to fall.\n\r", ch); i += number(1, 6); char_from_room(ch); char_to_room(ch, room); do_look(ch, "", 0); } GET_POS(ch) = POSITION_SITTING; if(i > GET_HIT(ch)) GET_HIT(ch) = 1; else GET_HIT(ch) -= i; } void do_palm( struct char_data *ch, char *arg, int cmd) { char arg1[MAX_STRING_LENGTH], arg2[MAX_STRING_LENGTH], buffer[MAX_STRING_LENGTH]; struct obj_data *sub_object; struct obj_data *obj_object; bool has=FALSE; if(!ch->desc || !ch->skills) { send_to_char("You are unable to use this command right now.\n\r", ch); return; } if(number(1,101) > ch->skills[SKILL_PALM].learned || !(HasClass(ch, CLASS_THIEF) && !IsIntrinsic(ch, SKILL_SPY))) { do_get(ch, arg, cmd); return; } argument_interpreter(arg, arg1, arg2); if(!*arg1) { send_to_char("Palm what doofus?\n\r",ch); } else if(*arg1 && !*arg2) { if(!str_cmp(arg1,"all")) { send_to_char("Palm everything? Are you mad?!?!\n\r", ch); return; } obj_object = get_obj_in_list_vis(ch, arg1, real_roomp(ch->in_room)->contents); if(obj_object) { if ((IS_CARRYING_N(ch) + 1 < CAN_CARRY_N(ch))) { if ((IS_CARRYING_W(ch) + obj_object->obj_flags.weight) < CAN_CARRY_W(ch)) { if (CAN_WEAR(obj_object,ITEM_TAKE)) { if (obj_object->in_room == NOWHERE) { obj_object->in_room = ch->in_room; } obj_from_room(obj_object); obj_to_char(obj_object, ch); act("You get $p.", 0, ch, obj_object, 0, TO_CHAR); if((obj_object->obj_flags.type_flag == ITEM_MONEY)) { if (obj_object->obj_flags.value[0]<1) obj_object->obj_flags.value[0] = 1; obj_from_char(obj_object); sprintf(buffer,"There %s %d coins.\n\r", obj_object->obj_flags.value[0] > 1 ? "were" : "was", obj_object->obj_flags.value[0]); send_to_char(buffer,ch); GET_GOLD(ch) += obj_object->obj_flags.value[0]; if (GET_GOLD(ch) > 100000 && obj_object->obj_flags.value[0] > 10000) { char buf[MAX_INPUT_LENGTH]; sprintf(buf,"%s just got %d coins!", GET_NAME(ch),obj_object->obj_flags.value[0]); log(buf); } extract_obj(obj_object); } } else { send_to_char("You can't take that.\n\r", ch); return; } } else { sprintf(buffer,"%s : You can't carry that much weight.\n\r", obj_object->short_description); send_to_char(buffer, ch); return; } } else { sprintf(buffer,"%s : You can't carry that many items.\n\r", obj_object->short_description); send_to_char(buffer, ch); return; } } else { sprintf(buffer,"You do not see a %s here.\n\r", arg1); send_to_char(buffer, ch); return; } } else { /* arg1 && arg2 */ if(!str_cmp(arg1,"all")) { send_to_char("Palm everything? Are you mad?!?!\n\r", ch); return; } sub_object = (struct obj_data *)get_obj_vis_accessible(ch, arg2); if (sub_object) { if(get_obj_in_list_vis(ch,arg2, ch->carrying)) has=TRUE; if (GET_ITEM_TYPE(sub_object) == ITEM_CONTAINER) { obj_object = get_obj_in_list_vis(ch, arg1, sub_object->contains); if (obj_object) { if (CheckForInsideTrap(ch, sub_object)) return; if ((IS_CARRYING_N(ch) + 1 < CAN_CARRY_N(ch))) { if (has || (IS_CARRYING_W(ch) + obj_object->obj_flags.weight) < CAN_CARRY_W(ch)) { if (CAN_WEAR(obj_object,ITEM_TAKE)) { if (!IS_SET(sub_object->obj_flags.value[1], CONT_CLOSED)) { obj_from_obj(obj_object); obj_to_char(obj_object, ch); act("You get $p from $P.",0,ch,obj_object,sub_object,TO_CHAR); if((obj_object->obj_flags.type_flag == ITEM_MONEY)) { if (obj_object->obj_flags.value[0]<1) obj_object->obj_flags.value[0] = 1; obj_from_char(obj_object); sprintf(buffer,"There %s %d coins.\n\r", obj_object->obj_flags.value[0] > 1 ? "were" : "was", obj_object->obj_flags.value[0]); send_to_char(buffer,ch); GET_GOLD(ch) += obj_object->obj_flags.value[0]; if (GET_GOLD(ch) > 100000 && obj_object->obj_flags.value[0] > 10000) { char buf[MAX_INPUT_LENGTH]; sprintf(buf,"%s just got %d coins!", GET_NAME(ch),obj_object->obj_flags.value[0]); log(buf); } extract_obj(obj_object); } } else { act("$P must be opened first.",1,ch,0,sub_object,TO_CHAR); } } else { send_to_char("You can't take that.\n\r", ch); } } else { sprintf(buffer,"%s : You can't carry that much weight.\n\r", obj_object->short_description); send_to_char(buffer, ch); } } else { sprintf(buffer,"%s : You can't carry that many items.\n\r", obj_object->short_description); send_to_char(buffer, ch); } } else { sprintf(buffer,"%s does not contain the %s.\n\r", sub_object->short_description, arg1); send_to_char(buffer, ch); } } else { sprintf(buffer,"%s is not a container.\n\r", sub_object->short_description); } } else { sprintf(buffer,"You do not see or have the %s.\n\r", arg2); send_to_char(buffer, ch); } } } void do_peek( struct char_data *ch, char *arg, int cmd) { char *argument; struct char_data *peeked; struct obj_data *dummy; if(!ch->desc || !ch->skills) { send_to_char("You are unable to use this command right now.\n\r", ch); return; } if ( IS_AFFECTED(ch, AFF_BLIND) ) { send_to_char("You can't see a damn thing, you're blinded!\n\r", ch); return; } if ( IS_DARK(ch->in_room) ) { if(!SUNPROBLEM(ch) && IS_AFFECTED(ch, AFF_INFRAVISION) && !IS_AFFECTED(ch, AFF_TRUE_SIGHT)) { send_to_char("Your infravision can't discern the items!\n\r",ch); return; } } if(!IS_IMMORTAL(ch)) { if( number(1,101) > ch->skills[SKILL_PEEK].learned || !(HasClass(ch, CLASS_THIEF) && !IsIntrinsic(ch, SKILL_SPY))) { do_look(ch, arg, cmd); LearnFromMistake(ch, SKILL_PEEK, 0, 95); return; } } argument = arg; if(!strn_cmp(arg,"at",2)) argument = arg+3; if(generic_find(argument, FIND_CHAR_ROOM, ch, &peeked, &dummy)) { show_char_to_char(peeked, ch, 1); } else { send_to_char("Heh heh, peek at whom?\n\r", ch); } } void do_berserk( struct char_data *ch, char *arg, int cmd) { struct affected_type af; if(!ch->skills) return; if (IS_NPC(ch)) { send_to_char("Funny, you don't feel like a real player ogre.\n\r",ch); return; } if (affected_by_spell(ch, SKILL_BERSERK)) { send_to_char("You have not recovered completely from the last time!\n\r", ch); return; } if(IS_AFFECTED2(ch, AFF2_BERSERK)) { send_to_char("But you allready are!\n\r",ch); return; } if (!ch->specials.fighting) { act("$n gets worked up into a lather and runs madly about!",TRUE, ch, 0, 0, TO_ROOM); send_to_char("You get all worked up over nothing and run madly about.\n\r", ch); send_to_char("You get the feeling that this works better in combat.\n\r", ch); return; } if(GET_RACE(ch) != RACE_OGRE) { send_to_char("Hey, you aint no ogre, go home wuss.\n\r",ch); return; } /* ok, we assume we have a fighting ogre */ if(number(1,101) > ch->skills[SKILL_BERSERK].learned) { send_to_char("You fail to go totally ape and kill everyone!\n\r",ch); act("$n starts snorting and huffing, but stops.",TRUE,ch,0,0,TO_ROOM); WAIT_STATE(ch, PULSE_VIOLENCE); } else { if (GET_POS(ch) >= POSITION_FIGHTING) { SET_BIT(ch->specials.affected_by2, AFF2_BERSERK); af.type = SKILL_BERSERK; af.duration = 24; af.modifier = 30; af.location = APPLY_AC; af.bitvector =0; affect_to_char(ch, &af); af.modifier = 1; af.location = APPLY_HASTE; affect_to_char(ch, &af); af.modifier = 3; af.location = APPLY_DAMROLL; affect_to_char(ch, &af); send_to_char("You fly into a furious rage!\n\r",ch); act("$n roars furiously and starts squashing $s opponents!\n\r",TRUE, ch,0, 0, TO_ROOM); } else { send_to_char("Maybe you should get on your feet first?\n\r",ch); } } } void do_makepotion(struct char_data *ch, char *argument, int cmd) { int i, ingredients=0 ,which_potion=0, match=0, j, max; bool object[5]; struct obj_data *o, *in_o, *next, *potion; struct room_data *rp; char buf[80]; extern struct index_data *obj_index; extern struct BrewMeister BrewList[MAX_POTIONS]; for(i=0;i<5;i++) /* very important indeed */ object[i] = 0; for(i=0; i<MAX_POTIONS; i++) { if(!strcmp(argument, BrewList[i].keyword)) { which_potion = i; for(j=0;j<5;j++) if(BrewList[which_potion].object[j] > 0) { ingredients++; /* number of valid ingredients */ } break; } } /* well, these (and only these) ingredients must be found in a */ /* cauldron that is sitting in the room. One communal one in the */ /* druid's tree, another sold by elvira in her shop :) and one in the*/ /* mages tower. */ if(!ingredients) { send_to_char("Eh, what? Have you got a gummi bear up your nose?\n\r", ch); send_to_char("You've never heard of such a potion!\n\r", ch); return; } #define CAULDRON 1531 rp = real_roomp(ch->in_room); if (!rp) return; for (o = rp->contents; o; o = o->next_content) { if( obj_index[o->item_number].virtual == CAULDRON ) { match = TRUE; /* o now points at our cauldron */ break; } } if(!match) { send_to_char("Egads, go find Sherlock, your cauldron is gone!\n\r", ch); return; } potion = read_object(BrewList[which_potion].object[5], VIRTUAL); /* is the caster high enough level to cast this? */ for(max=0,j=1;j<4;j++) { if(potion->obj_flags.value[j] >= 1) { for(i=0;i<MIN_LEVEL_NUM;i++) if(skill_info[potion->obj_flags.value[j]].min_level[i] < LOW_IMMORTAL) max=MAX(max, skill_info[potion->obj_flags.value[j]].min_level[i]); } } { char buf[80]; sprintf(buf,"Min brew level is: %d", max); log(buf); } extract_obj(potion); if(which_potion) if(!max || GetMaxLevel(ch) < max) { send_to_char("This brew is beyond your powers.\n\r", ch); return; } else { if(GetMaxLevel(ch) < 40) { send_to_char("This brew is beyond your powers.\n\r", ch); return; } } if(GET_ITEM_TYPE(o) == ITEM_CONTAINER) { /* it better be */ /* our cauldron must contain ONLY the right ingredients */ for(in_o=o->contains,i=0,match=ingredients; in_o; in_o = next) { next = in_o->next_content; i++; for(j=0;j<5;j++) { if (obj_index[in_o->item_number].virtual == BrewList[which_potion].object[j]) { if(!object[j]) { object[j] = TRUE; match--; } } } } } if(!i) { send_to_char("But the pot is empty?\n\r", ch); return; } if(ingredients != i || match != 0) { send_to_char("You don't have all the correct ingredients!\n\r", ch); send_to_char("Damn, you lost this batch.\n\r", ch); } else if (number(1,101) > ch->skills[SKILL_BREWING].learned) { act("$n accidentally lets a drop of sweat fall into the brew...", FALSE, ch, 0, 0, TO_ROOM); act("You stood too close to the cauldron. A drop of your sweat just fell in...", FALSE, ch, 0, 0, TO_CHAR); act("The cauldron overflows! Everything is ruined!", FALSE, ch, 0, 0, TO_ROOM); act("Next time pay more attention to your master... You just ruined this batch!", FALSE, ch, 0, 0, TO_CHAR); } else { potion = read_object(BrewList[which_potion].object[5], VIRTUAL); obj_to_room(potion, ch->in_room); act("$n carefully mixes some secret ingredients in a cauldron.", FALSE, ch, 0, 0, TO_ROOM); act("You carefully mix the ingredients of an age-old recipe.", FALSE, ch, 0, 0, TO_CHAR); act("Suddenly... Rainbows shoot out of the pot, and sparks fly!", FALSE, ch, 0, 0, TO_ROOM); act("Then in a burst of light, nothing remains but a bright flask!", FALSE, ch, 0, 0, TO_ROOM); act("Suddenly... Rainbows shoot out of the pot, and sparks fly!", FALSE, ch, 0, 0, TO_CHAR); act("Then in a burst of light, nothing remains but a bright flask!", FALSE, ch, 0, 0, TO_CHAR); } /* we always clean the pot, brew or fail. */ for(in_o = o->contains; in_o; in_o = next) { next = in_o->next_content; obj_from_obj(in_o); act("$p has vanished in a flash of bright light.", FALSE, ch, in_o, 0, TO_CHAR); act("$p has vanished in a flash of bright light.", FALSE, ch, in_o, 0, TO_ROOM); extract_obj(in_o); } } /* skill code pieces contributed by Gecko */ void add_skill(int nr, int taught_by, int class_use, int percent) { int i; skill_info[nr].spell_pointer = NULL; skill_info[nr].minimum_position = POSITION_STANDING; skill_info[nr].min_usesmana = 200; skill_info[nr].beats = 0; skill_info[nr].min_level[MIN_LEVEL_CLERIC] = LOKI+1; /* changed by Kiku */ skill_info[nr].min_level[MIN_LEVEL_MAGIC] = LOKI+1; /* New data structure */ skill_info[nr].min_level[MIN_LEVEL_DRUID] = LOKI+1; /* implementation. */ skill_info[nr].targets = TAR_IGNORE; skill_info[nr].spellfail = 0; skill_info[nr].percent = percent; /* added by Kiku */ for (i = 0; i < MAX_RACE_DENY; i++) skill_info[nr].race_deny[i] = 0; for (i = 0; i < MAX_RACE_INTRINSIC; i++) skill_info[nr].race_intrinsic[i] = 0; skill_info[nr].taught_by = taught_by; skill_info[nr].class_use = class_use; } void assign_skills() { add_skill(SKILL_SNEAK, TAUGHT_BY_THIEF | TAUGHT_BY_MONK, CLASS_THIEF | CLASS_MONK, 45); add_skill(SKILL_HIDE, TAUGHT_BY_THIEF | TAUGHT_BY_MONK, CLASS_THIEF | CLASS_MONK, 45); add_skill(SKILL_STEAL, TAUGHT_BY_THIEF, CLASS_THIEF, 45); add_skill(SKILL_BACKSTAB, TAUGHT_BY_THIEF, CLASS_THIEF, 45); add_skill(SKILL_PICK_LOCK, TAUGHT_BY_THIEF | TAUGHT_BY_MONK, CLASS_THIEF | CLASS_MONK, 45); add_skill(SKILL_KICK, TAUGHT_BY_WARRIOR | TAUGHT_BY_MONK, CLASS_WARRIOR | CLASS_MONK, 45); add_skill(SKILL_BASH, TAUGHT_BY_WARRIOR, CLASS_WARRIOR, 45); add_skill(SKILL_RESCUE, TAUGHT_BY_WARRIOR, CLASS_WARRIOR, 45); add_skill(SKILL_DUAL_WIELD, TAUGHT_BY_NINJA, CLASS_THIEF | CLASS_MONK | CLASS_WARRIOR, 95); add_skill(SKILL_FIRST_AID, TAUGHT_BY_HUNTER, CLASS_ALL, 95); add_skill(SKILL_SIGN, TAUGHT_BY_LORE, CLASS_ALL, 95); add_skill(SKILL_RIDE, TAUGHT_BY_NINJA, CLASS_ALL, 95); add_skill(SKILL_SWITCH_OPP, TAUGHT_BY_MONK | TAUGHT_BY_NINJA, CLASS_MONK | CLASS_WARRIOR, 45); add_skill(SKILL_DODGE, TAUGHT_BY_MONK, CLASS_WARRIOR | CLASS_MONK, 95); add_skill(SKILL_REMOVE_TRAP, TAUGHT_BY_HUNTER, CLASS_THIEF, 95); add_skill(SKILL_RETREAT, TAUGHT_BY_NINJA | TAUGHT_BY_MONK, CLASS_THIEF | CLASS_WARRIOR | CLASS_MONK, 45); add_skill(SKILL_QUIV_PALM, TAUGHT_BY_MONK, CLASS_MONK, 45); add_skill(SKILL_SAFE_FALL, TAUGHT_BY_MONK, CLASS_MONK, 95); add_skill(SKILL_FEIGN_DEATH, TAUGHT_BY_MONK, CLASS_MONK, 45); add_skill(SKILL_HUNT, TAUGHT_BY_HUNTER, CLASS_THIEF, 95); add_skill(SKILL_LOCATE_TRAP, TAUGHT_BY_HUNTER, CLASS_THIEF, 95); add_skill(SKILL_SPRING_LEAP, TAUGHT_BY_MONK, CLASS_MONK, 45); add_skill(SKILL_DISARM, TAUGHT_BY_NINJA | TAUGHT_BY_MONK, CLASS_WARRIOR | CLASS_MONK, 45); add_skill(SKILL_READ_MAGIC, TAUGHT_BY_LORE, CLASS_ALL, 95); add_skill(SKILL_EVALUATE, TAUGHT_BY_HUNTER, CLASS_THIEF, 95); add_skill(SKILL_SPY, TAUGHT_BY_NINJA, CLASS_THIEF, 45); add_skill(SKILL_DOORBASH, TAUGHT_BY_NINJA, CLASS_WARRIOR, 45); add_skill(SKILL_SWIM, TAUGHT_BY_SAILOR, CLASS_ALL, 60); add_skill(SKILL_CONS_UNDEAD, TAUGHT_BY_LORE, CLASS_ALL, 95); add_skill(SKILL_CONS_VEGGIE, TAUGHT_BY_LORE, CLASS_ALL, 95); add_skill(SKILL_CONS_DEMON, TAUGHT_BY_LORE, CLASS_ALL, 95); add_skill(SKILL_CONS_ANIMAL, TAUGHT_BY_LORE, CLASS_ALL, 95); add_skill(SKILL_CONS_REPTILE, TAUGHT_BY_LORE, CLASS_ALL, 95); add_skill(SKILL_CONS_PEOPLE, TAUGHT_BY_LORE, CLASS_ALL, 95); add_skill(SKILL_CONS_GIANT, TAUGHT_BY_LORE, CLASS_ALL, 95); add_skill(SKILL_CONS_OTHER, TAUGHT_BY_LORE, CLASS_ALL, 95); add_skill(SKILL_DISGUISE, TAUGHT_BY_NINJA, CLASS_THIEF, 45); add_skill(SKILL_CLIMB, TAUGHT_BY_NINJA, CLASS_THIEF, 45); add_skill(SKILL_INSET, TAUGHT_BY_LORE, CLASS_ALL, 95); add_skill(SKILL_BREWING, TAUGHT_BY_LORE, CLASS_DRUID, 95); add_skill(SKILL_BERSERK, TAUGHT_BY_ETTIN, 0, 80); add_skill(SKILL_PALM, TAUGHT_BY_THIEF, CLASS_THIEF, 45); add_skill(SKILL_PEEK, TAUGHT_BY_THIEF, CLASS_THIEF, 45); add_skill(SKILL_CONS_AVIAN, TAUGHT_BY_LORE, CLASS_ALL, 95); add_skill(SKILL_CONS_INSECT, TAUGHT_BY_LORE, CLASS_ALL, 95); /* Racial access and forbiddance goes below. Must ensure that */ /* skills (spells will) allow these via IsIntrinsic() checks. */ skill_info[SKILL_SWIM].race_deny[0] = RACE_DWARF; skill_info[SPELL_FAERIE_FIRE].race_intrinsic[0] = RACE_ELVEN; skill_info[SPELL_FAERIE_FIRE].race_intrinsic[1] = RACE_FAERIE; skill_info[SPELL_FAERIE_FIRE].race_intrinsic[2] = RACE_DROW; skill_info[SPELL_FAERIE_FOG].race_intrinsic[0] = RACE_ELVEN; skill_info[SPELL_FAERIE_FOG].race_intrinsic[1] = RACE_DROW; skill_info[SPELL_ENCHANT_WEAPON].race_intrinsic[0] = RACE_DWARF; skill_info[SPELL_ENCHANT_ARMOR].race_intrinsic[0] = RACE_DWARF; skill_info[SPELL_CURE_LIGHT].race_intrinsic[0] = RACE_FAERIE; skill_info[SPELL_WEB].race_intrinsic[0] = RACE_DROW; skill_info[SPELL_CHARM_PERSON].race_intrinsic[0] = RACE_VAMPIRE; skill_info[SPELL_FEAR].race_intrinsic[0] = RACE_VAMPIRE; skill_info[SKILL_BERSERK].race_intrinsic[0] = RACE_OGRE; skill_info[SKILL_HUNT].race_intrinsic[0] = RACE_ELVEN; skill_info[SKILL_PEEK].race_intrinsic[0] = RACE_FAERIE; skill_info[SKILL_RETREAT].race_intrinsic[0] = RACE_HALFLING; skill_info[SKILL_RETREAT].race_intrinsic[1] = RACE_DRAAGDIM; skill_info[SKILL_SPY].race_intrinsic[0] = RACE_MFLAYER; skill_info[SKILL_PALM].race_intrinsic[0] = RACE_HALFLING; skill_info[SKILL_PALM].race_intrinsic[1] = RACE_DRAAGDIM; skill_info[SKILL_EVALUATE].race_intrinsic[1] = RACE_DWARF; skill_info[SKILL_EVALUATE].race_intrinsic[0] = RACE_HALFLING; skill_info[SKILL_SAFE_FALL].race_intrinsic[0] = RACE_VAMPIRE; skill_info[SKILL_PICK_LOCK].race_intrinsic[0] = RACE_GNOME; skill_info[SKILL_REMOVE_TRAP].race_intrinsic[0] = RACE_GNOME; }