Hi there. This is a public release of my first area, "Rome". The statistics are the following: Rome: approx 70 rooms, 35 mobs, 30 objects. It's a good area for mid-upper levels with some excellent statted objects. Rome should attach in the great eastern desert at room 5027, going west to room 12067. Note: I release Rome to the general public and you may use or modify the area as you see fit. All I ask is that object number 12050 is left in the object and zone files. I wish you luck. Regards, Onivel of Jedi INSTALLATION NOTES FOR ROME The world and zone files should go in with no problems, for a "standard" dikumud. However: 1) Jedi uses an "asciiflag" system, where the bitvectors are represented as letters in the mob and object files. (Instead of 3, it would be represented as "AB". This makes it easier to add/subtract/modify flags on objects and mobs. Especially when you get into the larger numbers. You have two choices here: I've included the code to "read" these flags and turn them into bitvector numbers at bootup. Or, you can go through and change all of the flags back to bitvectors. 2) Jedi uses a lot of "special" flags, such as "LIMITED", "NO<class>", etc. If your code does not support these, they will have to be removed. I've also included some documentation of each letter-flag correspondance. 3) The object files use a 5th value on the values[] array. This corresponds to the minimum level a character must be to use/wield/wear the object. These will have to be removed if your code does not support this option. 4) Jedi uses an extended, alphabetical spell set. The spell numbers for scrolls and potions do not match standard diku. Thus, the below is the spell reference numbers for the scrolls/potions/wands/staffs that are used on Jedi. You will have to convert those objects to the equivilent numbers that your MUD uses. #define SPELL_AERIAL_SERVANT 1 #define SPELL_AID 2 #define SPELL_ANIMATE_DEAD 3 #define SPELL_ARMOR 4 #define SPELL_BANISHMENT 5 #define SPELL_BLESS 6 #define SPELL_BLINDNESS 7 #define SPELL_BURNING_HANDS 8 #define SPELL_CALL_LIGHTNING 9 #define SPELL_CALM 10 #define SPELL_CAUSE_CRITIC 11 #define SPELL_CAUSE_LIGHT 12 #define SPELL_CAUSE_SERIOUS 13 #define SPELL_CHARM_PERSON 14 #define SPELL_CHILL_TOUCH 15 #define SPELL_CLONE 16 #define SPELL_COLOUR_SPRAY 17 #define SPELL_CONJURE_ELEMENTAL 18 #define SPELL_CONTROL_WEATHER 19 #define SPELL_CREATE_FOOD 20 #define SPELL_CREATE_WATER 21 #define SPELL_CURE_BLIND 22 #define SPELL_CURE_CRITIC 23 #define SPELL_CURE_LIGHT 24 #define SPELL_CURE_SERIOUS 25 #define SPELL_CURSE 26 #define SPELL_DEATHS_DOOR 27 #define SPELL_DETECT_ALIGNMENT 28 #define SPELL_DETECT_INVISIBLE 29 #define SPELL_DETECT_MAGIC 30 #define SPELL_DETECT_POISON 31 #define SPELL_DISINTEGRATE 32 #define SPELL_DISPEL_EVIL 33 #define SPELL_DISPEL_GOOD 34 #define SPELL_EARTHQUAKE 35 #define SPELL_ENCHANT_ARMOR 36 #define SPELL_ENCHANT_WEAPON 37 #define SPELL_ENERGY_DRAIN 38 #define SPELL_FEAR 39 #define SPELL_FINDFAMILIAR 40 #define SPELL_FIREBALL 41 #define SPELL_FIREBLAST 42 #define SPELL_FLAMESTRIKE 43 #define SPELL_GATE_I 44 #define SPELL_GATE_II 45 #define SPELL_GROUP_HEAL 46 #define SPELL_GROUP_INFRAVISION 47 #define SPELL_GROUP_INVISIBLE 48 #define SPELL_HARM 49 #define SPELL_HASTE 50 #define SPELL_HEAL 51 #define SPELL_HOLD 52 #define SPELL_ICE_STORM 53 #define SPELL_INFRAVISION 54 #define SPELL_INVISIBLE 55 #define SPELL_LIGHTNING_BOLT 56 #define SPELL_LOCATE_OBJECT 57 #define SPELL_MAGIC_MISSILE 58 #define SPELL_MAGICAL_VESTMENT 59 #define SPELL_METEORSWARM 60 #define SPELL_MONSUM_I 61 #define SPELL_MONSUM_II 62 #define SPELL_MONSUM_III 63 #define SPELL_PETRIFICATION 64 #define SPELL_POISON 65 #define SPELL_POLYMORPH_I 66 #define SPELL_POLYMORPH_II 67 #define SPELL_POLYMORPH_III 68 #define SPELL_POLYMORPH_OTHER 69 #define SPELL_PROTECT_FROM_EVIL 70 #define SPELL_PROTECT_FROM_GOOD 71 #define SPELL_REANIMATE 72 #define SPELL_REGENERATE 73 #define SPELL_REJUVENATE 74 #define SPELL_REMOVE_CURSE 75 #define SPELL_REMOVE_PARALYSIS 76 #define SPELL_REMOVE_POISON 77 #define SPELL_RESTORE 78 #define SPELL_RESURRECT 79 #define SPELL_SANCTUARY 80 #define SPELL_SENSE_LIFE 81 #define SPELL_SHOCKING_GRASP 82 #define SPELL_SLAY 83 #define SPELL_SLEEP 84 #define SPELL_SPIRITUAL_HAMMER 85 #define SPELL_STONE_SKIN 86 #define SPELL_STRENGTH 87 #define SPELL_SUMMON 88 #define SPELL_TELEPORT 89 #define SPELL_INFORMATION 90 #define SPELL_WATERBREATHING 91 #define SPELL_WATERWALK 92 #define SPELL_WEB 93 #define SPELL_WORD_OF_DEATH 94 #define SPELL_WORD_OF_RECALL 95 Here are the ascii->flag conversions: ACT_SPEC A ACT_SENTINEL B ACT_SCAVENGER C ACT_NICE_THIEF E ACT_AGGRESSIVE F ACT_STAY_ZONE G ACT_WIMPY H ACT_NOSUMMON I ACT_MULTHIT0 J ACT_MULTHIT1 K ACT_MEMORY L ACT_NOPURGE O AFF_INVISIBLE B AFF_DETECT_INVISIBLE D AFF_SANCTUARY H AFF_INFRAVISION O AFF_SNEAK S AFF_HIDE T ITEM_TAKE A ITEM_WEAR_FINGER B ITEM_WEAR_NECK C ITEM_WEAR_BODY D ITEM_WEAR_HEAD E ITEM_WEAR_LEGS F ITEM_WEAR_FEET G ITEM_WEAR_HANDS H ITEM_WEAR_ARMS I ITEM_WEAR_SHIELD J ITEM_WEAR_ABOUT K ITEM_WEAR_WAISTE L ITEM_WEAR_WRIST M ITEM_WIELD N ITEM_HOLD O ITEM_GLOW A ITEM_HUM B ITEM_EVIL E ITEM_INVISIBLE F ITEM_MAGIC G ITEM_NODROP H ITEM_BLESS I ITEM_ANTI_GOOD J ITEM_ANTI_EVIL K ITEM_ANTI_NEUTRAL L ITEM_NEUTRAL M ITEM_GOOD N ITEM_NO_MORTAL O ITEM_NO_MAGE P ITEM_NO_CLERIC Q ITEM_NO_THIEF R ITEM_NO_WARRIOR S ITEM_NO_PALADIN T ITEM_NO_APALADIN U ITEM_NO_NINJA V ITEM_NO_JEDI W ITEM_NO_SOHEI X ITEM_LIMITED Y ITEM_NOPURGE Z ITEM_NORENT a ITEM_NODONATE c The code to convert an asciiflag to a bitvector is: #define BITSHIFT(c) (c - 'A') #define FLAG(cr) (BITSHIFT(cr) <= 25 ? (1 << BITSHIFT(cr)) : \ ((BITSHIFT(cr)-6) < 31 ? (1 << (BITSHIFT(cr)-6)): 0)) long flag_convert(char *argument) { long flagval = 0; int i; char buf[52]; strcpy(buf, argument); for (i = 0; i < strlen(argument); i++) if (buf[i] != '0') flagval += FLAG(buf[i]); else return(flagval); return(flagval); } Below is a list of the special assignment routines for the mobs: /* ROME SPECIAL PROCEDURES */ mob 12030 = mob_defender mob 12031 = mob_defender mob 12038 = mob_defender mob 12033 = mob_defender mob 12020 = mob_magic_user mob 12025 = mob_magic_user mob 12034 = mob_magic_user /* The "mob_defender" code. (VERY nasty) */ #define ATK_AREA 1 << 0 /* Throw "area attack spells" */ #define ATK_TANK 1 << 1 /* Target the tank for special treatment */ #define ATK_MAGE 1 << 2 /* Target the mage for special treatment */ #define ATK_CLER 1 << 3 /* Target the cleric for special treatment */ #define ATK_HEAL 1 << 4 /* Mob heals self during combat */ #define ATK_PETS 1 << 5 /* Instantly kills any "pets" of pc's */ #define ATK_DEF_ONLY 1 << 6 /* Only use the ATK_TANK, ATK_CLER, and ATK_MAGE portions of the routing if defending a specific object. */ #define ATK_WEAK 1 << 7 /* Polish off the weakling */ #define ATK_ARMIES 1 << 8 /* Banzai any "armies" that are gathering */ #define ATK_NOFLEE 1 << 9 /* Prevent fleeing -- VERY nasty option */ #define ATK_THROW_ROOM 1 << 10 /* Throw players out of room for damage. */ #define MOB_NUM 0 /* Do not change these */ #define ATK_TYPE 1 #define DEF_ITEM 2 #define EXIT_BVECT 3 #define EXIT_ROOM 4 #define CMD_FLEE 151 /* Change this to whatever command number your #define CMD_RETREAT 282 and retreat commands are. */ #define NUM_MOBS 4 /* Number of mobs that are in the definition array */ const int def_data[NUM_MOBS][5] = { {12038, ATK_THROW_ROOM | ATK_TANK | ATK_DEF_ONLY | ATK_HEAL | ATK_MAGE | ATK_CLER | ATK_WEAK | ATK_ARMIES | ATK_AREA | ATK_PETS, 12032, 0, -1}, /* Jupiter */ {12031, ATK_THROW_ROOM | ATK_TANK | ATK_AREA | ATK_PETS | ATK_ARMIES | ATK_HEAL | ATK_NOFLEE, -1, DIR_UP, 12052}, /* Venus */ {12032, ATK_AREA | ATK_ARMIES | ATK_THROW_ROOM | ATK_PETS | ATK_HEAL | ATK_NOFLEE, -1, DIR_UP, 12056}, /* Mars */ {12033, ATK_AREA | ATK_PETS | ATK_THROW_ROOM | ATK_NOFLEE, -1, DIR_UP, 12059}, /* Mercury */ }; /* The above array makes the procedure generalized enough that it can be attached to as many other mobs on your MUD as you wish. The format of each entry is: {<mob vnum>, <behavior flags>, <object to be defended, -1 if none>, <direction to block>, <blocking room mob is in, -1 if none>} */ int mob_defender (struct char_data *ch, int cmd, char *argument) { /* Written by Onivel of Jedi, 4-93. I make no claims that this is the cleanest or best way of doing things. I do claim that it works and and does what we want it to do on Jedi. -- If you like it, feel free to use it. If not *shrug* */ extern struct char_data *mob_proto; extern struct obj_data *obj_proto; struct char_data *tch, *victim1=0, *victim2=0, *victim3=0, *k, *l; struct obj_data *dummy, *next_obj; struct follow_type *f, *g; bool mob_found = FALSE; bool npc_found = FALSE; bool nasty_things = FALSE; bool throw_wall = FALSE; char buf[MAX_STRING_LENGTH]; char buf2[MAX_STRING_LENGTH]; int i, ii, bits, armies = 0, x = 0, exits = 0; /* Deal with blocking the exits first. -- The old "You'll have to go through me first!" mentality. */ if ((cmd <= 10 && cmd > 0) || cmd == CMD_FLEE || cmd == CMD_RETREAT) { for(i = 0;i<NUM_MOBS; i++) if (real_room(def_data[i][EXIT_ROOM]) == ch->in_room) { mob_found = TRUE; break; } if (!mob_found) /* No blocking function for this room */ return FALSE; sprintf(buf,"%s", mob_proto[real_mobile(def_data[i][MOB_NUM])].player.short_descr); if ((cmd == CMD_FLEE || cmd == CMD_RETREAT) && IS_SET(def_data[i][ATK_TYPE], ATK_NOFLEE)) { sprintf(buf2,"%s prevents you from %sing!\n\r", buf, cmd == CMD_FLEE ? "flee" : "retreat"); send_to_char(buf2,ch); sprintf(buf2,"%s prevents %s from %sing!\n\r",buf,GET_NAME(ch), cmd == CMD_FLEE ? "flee" : "retreat"); send_to_room_except(buf2,ch->in_room, ch); return TRUE; } if (IS_SET(def_data[i][EXIT_BVECT], 1<<cmd-1)) { sprintf(buf,"%s", mob_proto[real_mobile(def_data[i][MOB_NUM])].player.short_descr); sprintf(buf2,"%s tells you, 'You have to go through me first.'\n\r",buf); send_to_char(buf2,ch); sprintf(buf2,"%s blocks %s's way!\n\r",buf,GET_NAME(ch)); send_to_room_except(buf2,ch->in_room,ch); return TRUE; } return FALSE; } /* Make sure we are dealing with a "heartbeat mob call" */ if (cmd != 0) return FALSE; for(i = 0; i < NUM_MOBS && real_mobile(def_data[i][MOB_NUM]) != ch->nr; i++); if (i > NUM_MOBS) { syslog("MOB_OUT_OF_RANGE", OFF, 32, TRUE); return FALSE; } /* If there is an "army" in the room, berzerk them! */ if (!ch->specials.fighting && GET_POS(ch) > POSITION_SLEEPING && IS_SET(def_data[i][ATK_TYPE], ATK_ARMIES)) { armies = 0; for (tch = world[ch->in_room].people; tch; tch = tch->next_in_room) if ((GET_LEVEL(tch) < LVL_IMM && !IS_NPC(tch))) armies++; if (!number(0,3) && (armies > (GET_LEVEL(ch)>>2))) { act("$n yells, 'ATTACK!!!!!!'",FALSE,ch,0,0,TO_ROOM); for(tch=character_list; tch; tch=k) { k = tch->next; if (((!IS_NPC(tch) && GET_LEVEL(tch) < LVL_IMM) || (IS_NPC(tch) && ch != tch)) && tch->in_room == ch->in_room) { hit(ch, tch, TYPE_UNDEFINED); if (ACT_CHK(ch,F_MOB,ACT_MULTHIT1)) hit(ch, tch, TYPE_UNDEFINED); } } } return TRUE; } /* Deal with the pets. */ if (IS_SET(def_data[i][ATK_TYPE], ATK_PETS) && !IS_AFFECTED(ch, AFF_CHARM)) { for(tch = world[ch->in_room].people; tch; tch = l) { l = tch->next_in_room; if (tch && IS_NPC(tch) && tch != ch) { act("$n screams in pain as $N's glare kills it!",1,tch,0,ch, TO_ROOM); death_cry(tch); extract_char(tch); npc_found = TRUE; } } if (npc_found) return FALSE; } /* Find out if the mob is fighting and WHO he is fighting, along with his master. (If he has one) */ if (!ch->specials.fighting || GET_POS(ch) != POSITION_FIGHTING) return FALSE; else tch = ch->specials.fighting; if (tch->master) k = tch->master; else k = tch; /* Deal with class specific actions. This should "short-circut" if the ATK_DEF_ONLY is set and the mob doesn't have the specified item to "defend" in it's inventory or equipment list. */ g = 0; dummy = 0; if (def_data[i][DEF_ITEM] != NOWHERE) { for (dummy = ch->carrying; dummy; dummy = next_obj) { next_obj = dummy->next_content; if (obj_index[dummy->item_number].virtual == def_data[i][DEF_ITEM]) { bits = 1; break; } } if (!bits) for (ii=0; ii < MAX_WEAR; ii++) if (ch->equipment[ii] && obj_index[ch->equipment[ii]->item_number].virtual == def_data[i][DEF_ITEM]) { bits = 1; break; } } else bits = 0; dummy = 0; if ((IS_SET(def_data[i][ATK_TYPE], ATK_DEF_ONLY) && bits) || !IS_SET(def_data[i][ATK_TYPE], ATK_DEF_ONLY)) { /* Chose the possible victims */ for(f=k->followers; f; f=g) { g = f->next; if (f->follower && GET_CLASS(f->follower) == CLASS_MAGIC_USER && f->follower->specials.fighting) { victim1 = f->follower; } else if (f->follower && GET_CLASS(f->follower) == CLASS_CLERIC && f->follower->specials.fighting) { victim2 = f->follower; } else if (f->follower && GET_HIT(f->follower) < 50 && f->follower->specials.fighting) { victim3 = f->follower; } } /* Maim the Mage */ if (IS_SET(def_data[i][ATK_TYPE], ATK_MAGE) && !number(0,2) && victim1 && victim1->specials.fighting) { act("$n utters the words 'ezis rof no eno siht yrt'.", 1,ch,0,0,TO_ROOM); cast_gen_offensive_spells(GET_LEVEL(ch), ch, "", SPELL_TYPE_SPELL, victim1, 0,SPELL_WORD_OF_DEATH); if (GET_POS(victim1) > POSITION_DEAD && !number(0,1)) { damage(ch, victim1, GET_LEVEL(ch), SKILL_PUMMEL); if (GET_POS(victim1) > POSITION_RESTING) { GET_POS(victim1) = POSITION_RESTING; WAIT_STATE(victim1, 2*PULSE_VIOLENCE); } } nasty_things = TRUE; } /* Clobber the Cleric */ if (IS_SET(def_data[i][ATK_TYPE], ATK_CLER) && victim2 && !number(0,2) && victim2->specials.fighting) { if (ch != victim2->specials.fighting) { sprintf(buf,"MALFUNCTION, Acid breath, victim: %s, attaker: %s", GET_NAME(victim2), GET_NAME(victim2->specials.fighting)); log(buf); return; } act("$n utters the words 'Diplorioulus Desoto'.",1,ch,0,0,TO_ROOM); cast_npc_breath_spells(GET_LEVEL(ch), ch, "", SPELL_TYPE_SPELL, victim2, 0,SPELL_ACID_BREATH); nasty_things = TRUE; if (GET_POS(victim2) > POSITION_DEAD && !number(0,1)) { damage(ch, victim2, GET_LEVEL(ch), SKILL_BASH); if (GET_POS(victim2) > POSITION_SITTING) { GET_POS(victim2) = POSITION_SITTING; WAIT_STATE(victim2, 2*PULSE_VIOLENCE); } } } /* Whack the Weakling */ if (IS_SET(def_data[i][ATK_TYPE], ATK_WEAK) && !number(0,2) && victim3 && victim3->specials.fighting) { act("$n utters the words 'Jicondulus Kodalar'.",1,ch,0,0,TO_ROOM); cast_gen_offensive_spells(GET_LEVEL(ch), ch, "", SPELL_TYPE_SPELL, victim3, 0,SPELL_HARM); nasty_things = TRUE; } /* Trash the tank... heh heh heh */ if (IS_SET(def_data[i][ATK_TYPE], ATK_TANK) && !number(0,2) && tch->specials.fighting) { if (tch->affected) { while (tch->affected) affect_remove(tch, tch->affected); sprintf(buf,"%s causually points in your direction and you feel a" " throbbing\n\rpain!\n\r",ch->player.short_descr); send_to_char(buf,ch); sprintf(buf,"%s casually points towards %s's and there is a huge\n\r " "flash of light!\n\r",ch->player.short_descr, GET_NAME(tch)); send_to_room_except(buf,ch->in_room, tch); } damage(ch, tch, GET_LEVEL(ch), SKILL_BASH); cast_gen_offensive_spells(GET_LEVEL(ch), ch, "", SPELL_TYPE_SPELL, tch, 0, SPELL_DISINTEGRATE); if (GET_POS(tch) > POSITION_SITTING) { GET_POS(tch) = POSITION_STUNNED; WAIT_STATE(tch, 2*PULSE_VIOLENCE); } nasty_things = TRUE; } } /* The above is only done if the mob has the object to be defended or if the ATK_DEF_ONLY bit is NOT set. The area attacks are below. */ if (IS_SET(def_data[i][ATK_TYPE], ATK_AREA)) { if (!number(0,3)) { switch(number(0,3)) { case 0: act("$n utters the word 'THOR!'.",1,ch,0,0,TO_ROOM); cast_gen_area_off_spells(GET_LEVEL(ch), ch, "", SPELL_TYPE_SPELL, 0, 0,SPELL_FIREBLAST); break; case 1: act("$n utters the word 'FACQULAR!'.",1,ch,0,0,TO_ROOM); cast_gen_area_off_spells(GET_LEVEL(ch),ch,"",SPELL_TYPE_SPELL, 0, 0,SPELL_ICE_STORM); break; case 2: act("$n utters the word 'YALAMANCHILI!'.",1,ch,0,0,TO_ROOM); cast_gen_area_off_spells(GET_LEVEL(ch),ch,"",SPELL_TYPE_SPELL,0, 0,SPELL_METEORSWARM); break; case 3: act("$n utters something unintelligible.",1,ch,0,0,TO_ROOM); cast_gen_area_off_spells(GET_LEVEL(ch),ch,"",SPELL_TYPE_SPELL,0, 0,SPELL_EARTHQUAKE); break; default: break; } nasty_things = TRUE; } } /* Throw a character from the room or up against a wall. */ if (IS_SET(def_data[i][ATK_TYPE], ATK_THROW_ROOM) && GET_POS(ch) == POSITION_FIGHTING && ch->specials.fighting) { for (tch = world[ch->in_room].people; tch; tch = k) { k = tch->next_in_room; if (!number(0,2) && tch->specials.fighting == ch) { exits = 0; for (armies = 0; armies <=9; armies++) if (world[ch->in_room].dir_option[cmd]) exits++; if (!exits) break; else { exits = number(0,exits); for (armies = 0; x!=exits && armies <=9; armies++) if (world[ch->in_room].dir_option[armies]) x++; if ((ch && ch->in_room != NOWHERE && IS_SET(world[ch->in_room].dir_option[x]->exit_info, EX_CLOSED)) || (IS_SET(def_data[i][EXIT_BVECT], 1<<x ) && world[ch->in_room].number == def_data[i][EXIT_ROOM]) || (IS_SET(world[world[ch->in_room].dir_option[x]->to_room].room_flags, DEATH))) throw_wall = TRUE; if (!throw_wall) { stop_fighting(tch); char_from_room(tch); char_to_room(tch,world[ch->in_room].dir_option[x]->to_room); if (tch == ch->specials.fighting) stop_fighting(ch); sprintf(buf,"%s grabs you by the neck and throws you out of the " "room!!\n\r\n\r", GET_NAME(ch)); send_to_char(buf,tch); sprintf(buf,"%s comes hurtling into the room!\n\r",GET_NAME(tch)); send_to_room_except(buf,tch->in_room,tch); do_look(tch,"\0",15,0,0); GET_POS(tch) = POSITION_SITTING; GET_HIT(tch) -= number(GET_LEVEL(ch), 3*GET_LEVEL(ch)); GET_HIT(tch) = MAX(0,GET_HIT(tch)); WAIT_STATE(tch, 3*PULSE_VIOLENCE); sprintf(buf,"%s gets a hold of %s's neck and visciously throws\n\r" "%s out of the room!!!\n\r", GET_NAME(ch), GET_NAME(tch), HMHR(tch)); send_to_room(buf,ch->in_room); break; } else { sprintf(buf,"%s picks you up and bodyslams you to the ground!\n\r", GET_NAME(ch)); send_to_char(buf,tch); GET_POS(tch) = POSITION_STUNNED; GET_HIT(tch) -= number(GET_LEVEL(ch), 3*GET_LEVEL(ch)); GET_HIT(tch) = MAX(0,GET_HIT(tch)); WAIT_STATE(tch, 3*PULSE_VIOLENCE); sprintf(buf,"%s gets a hold of %s and bodyslams " "%s to the ground!!!\n\r", GET_NAME(ch), GET_NAME(tch), HMHR(tch)); send_to_room_except(buf,ch->in_room,tch); } } } } } /* Last, but not least, combat healing. */ if (IS_SET(def_data[i][ATK_TYPE], ATK_HEAL)) { if (!number(0, (nasty_things ? 2 : 3))) { act("$n utters the words 'pzar maximus'.",1,ch,0,0,TO_ROOM); GET_HIT(ch) += number ((GET_MAX_HIT(ch)/10), (GET_MAX_HIT(ch)/6)); GET_HIT(ch) = MIN(GET_HIT(ch), GET_MAX_HIT(ch)); } } return FALSE; }