This snippet is fairly simple to install, the only major change is to do_cast and pasting in the other support functions. What it will do is remove the wait_state that is normally applied after casting a spell and instead makes the caster concentrate on the spell before hand. It should basically elminate spamming casting commands and allows for a greater realism in spellcasting. This snippet was installed into a stock Quickmud, but should be appliable to a stock ROM or adapted to most derivs being that not many people have changed how casting has been handled. // merc.h // under the i am lazy category :P #define stc send_to_char //add defines for the character's action state #define ACTION_NONE 0 #define ACTION_CASTING 1 //in struct char_data sh_int action[2]; sh_int spell_vars[5]; void * vo; // magic.c // in the local functions near the top of the file /* imported functions */ bool remove_obj args ((CHAR_DATA * ch, int iWear, bool fReplace)); void wear_obj args ((CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace)); + void stop_spell args ((CHAR_DATA *ch)); // now the fun part, change do_cast into to two seperate functions, the first one checks for // basic legality and then sets the variables in the char_data // in function do_cast find the say_spell line and start chopping - if (str_cmp (skill_table[sn].name, "ventriloquate")) - say_spell (ch, sn); - WAIT_STATE (ch, skill_table[sn].beats); - if (number_percent () > get_skill (ch, sn)) - { - send_to_char ("You lost your concentration.\n\r", ch); - check_improve (ch, sn, FALSE, 1); - ch->mana -= mana / 2; - } - else - { - ch->mana -= mana; - if (IS_NPC (ch) || class_table[ch->class].fMana) - /* class has spells */ - (*skill_table[sn].spell_fun) (sn, ch->level, ch, vo, target); - else - (*skill_table[sn].spell_fun) (sn, 3 * ch->level / 4, ch, vo, target); - check_improve (ch, sn, TRUE, 1); - } - - if ((skill_table[sn].target == TAR_CHAR_OFFENSIVE - || (skill_table[sn].target == TAR_OBJ_CHAR_OFF - && target == TARGET_CHAR)) && victim != ch - && victim->master != ch) - { - CHAR_DATA *vch; - CHAR_DATA *vch_next; - - for (vch = ch->in_room->people; vch; vch = vch_next) - { - vch_next = vch->next_in_room; - if (victim == vch && victim->fighting == NULL) - { - check_killer (victim, ch); - multi_hit (victim, ch, TYPE_UNDEFINED); - break; - } - } - } - - return; - } // replace all of that with this ch->spell_vars[0] = sn; ch->spell_vars[1] = ch->level; ch->spell_vars[2] = target; ch->spell_vars[4] = mana; ch->vo = vo; ch->spell_vars[3] = skill_table[sn].beats / 6; ch->action[0] = ACTION_CASTING; stc ("You begin to focus on casting a spell.\n\r", ch); act ("$n begins to cast a spell.", ch, NULL, NULL, TO_ROOM); return; } // Now add in the release function that is called when the timer reaches 0 // has_object is a quick hack function that takes OBJ_DATA and checks if the player carries it bool has_object ( CHAR_DATA *ch, OBJ_DATA *obj) { OBJ_DATA *obj1; for ( obj1 = ch->carrying; obj != NULL; obj = obj->next_content ) { if ( obj1 == obj ) return TRUE; } return FALSE; } void release_spell( int sn, int level, CHAR_DATA *ch, void *vo, int target) { OBJ_DATA *obj; CHAR_DATA *victim = NULL; /* check to be sure the target is still there */ switch (target) { default: break; case TARGET_CHAR: victim = (CHAR_DATA *) vo; if (victim == NULL || victim->in_room != ch->in_room) { send_to_char ("They are no longer here.\n\r", ch); stop_spell( ch ); return; } if (is_safe (ch, victim) && ch != victim) { send_to_char ("Something isn't right...\n\r", ch); stop_spell( ch ); return; } break; case TARGET_OBJ: obj = ( OBJ_DATA *) vo; if ( obj == NULL || (obj->in_room != ch->in_room && !has_object(ch, obj))) { stc ("That item is no longer here.\n\r", ch); stop_spell( ch); return; } break; } if (number_percent () > get_skill(ch, sn)) { send_to_char ("You lost your concentration.\n\r", ch); check_improve (ch, sn, FALSE, 1); ch->mana -= ch->spell_vars[4] / 2; } else { ch->mana -= ch->spell_vars[4]; if (IS_NPC (ch) || class_table[ch->class].fMana) /* class has spells */ (*skill_table[sn].spell_fun) (sn, level, ch, vo, target); else (*skill_table[sn].spell_fun) (sn, 3 * level / 4, ch, vo, target); check_improve (ch, sn, TRUE, 1); if (str_cmp (skill_table[sn].name, "ventriloquate")) say_spell ( ch); } ch->action[0] = ACTION_NONE; if ((skill_table[sn].target == TAR_CHAR_OFFENSIVE || (skill_table[sn].target == TAR_OBJ_CHAR_OFF && target == TARGET_CHAR)) && victim != ch && victim->master != ch) { CHAR_DATA *vch; CHAR_DATA *vch_next; for (vch = ch->in_room->people; vch; vch = vch_next) { vch_next = vch->next_in_room; if (victim == vch && victim->fighting == NULL) { check_killer (victim, ch); multi_hit (victim, ch, TYPE_UNDEFINED); break; } } } return; } // add in stop_spell to reset the various data void stop_spell( CHAR_DATA *ch ) { if (ch->action[0] != ACTION_CASTING) return; ch->spell_vars[0] = 0; ch->spell_vars[1] = 0; ch->spell_vars[2] = 0; ch->vo = NULL; ch->mana -= ch->spell_vars[4] / 4; ch->action[0] = ACTION_NONE; return; } // the update_casting is called from violence_update decreases the timer and calls // release_spell when the timer reaches 0 void update_casting( CHAR_DATA *ch ) { if ( --ch->spell_vars[3] == 0) release_spell( ch->spell_vars[0], ch->spell_vars[1], ch, ch->vo, ch->spell_vars[2]); else { stc("You continue to draw energy for the spell.\n\r", ch); act("$n continues to recite a spell.", ch, NULL, NULL, TO_ROOM); } return; } // Thats it for magic.c now on to fight.c to add the update casting call // add update_casting to the local functions listing void raw_kill args ((CHAR_DATA * victim)); void set_fighting args ((CHAR_DATA * ch, CHAR_DATA * victim)); void disarm args ((CHAR_DATA * ch, CHAR_DATA * victim)); + void update_casting args((CHAR_DATA *ch )); // in violence_update at the beginning of the first for() loop for (ch = char_list; ch != NULL; ch = ch_next) { ch_next = ch->next; + if ( ch->action[0] == ACTION_CASTING ) + update_casting(ch); if ((victim = ch->fighting) == NULL || ch->in_room == NULL) continue; There you go, this is the very basic form but should be enough to get you started. Some other simple things I have done to work along with this is to add messages to each spell that are used instead of say_spell to allow spells to be more unique. Just alter the message in update_casting and get rid of say_spell. Also added a check in bool damage so that a mage in the middle of casting a spell that takes damage has a chance of losing their concentration. I also added a do_stop command ( basically a call to stop_spell) so spell casting can be halted. The only major problem I ran into was that the immortal command do_at had to be reworked into a direct call to the spell function instead of a normal do_cast call. Any questions I can normally be found lurking about the major mud boards or hacking away at my mud lanera.net port 7000