A chain lightning spell that uses events to hit one victim at a time then move on to the next one (as set up, it moves every PULSE_VIOLENCE/2) Author: Mike Stilson As always, this code works for me. If this code breaks your mud, wipes your hard disk, blows up large portions of your neighborhood, or brings about the downfall of life as we know it, I'm not responsible. Use it at your own risk. Any comments, suggestions (other than what orifice I can stuff this in), or improvements/changes send to the above address. It's been tested pretty heavily and so far we only had one crash ever, and it wasn't reproducable (probably bad interaction with a script on one of the mobs). This code is compatible with my weapon spell snippet. It can be added with no problem. I'm not 100% happy or done with this. The original implementation is supposed to have the damage decrease with each hop, but at the time it was a little more involved than I felt like doing for a quick spell. It shouldn't require too much to add it, just being lazy. There are a couple potential problems in it involving quitting (which I don't allow, hafta rent at an inn) and a couple other minor things involving timing, but I've yet to have a problem. If you use this in your mud, all I ask is you drop me a note letting me know. If you wanna put me in the credits, that's up to you. Add this to spells.c /* * This spell is special because we use an event to handle this spell. * cl is the event_obj stored in the player struct. * cl_targets is a linked list of all of the original targets in the room. * When created, it skips self, pc's, charmed mobs. * * TODO: Add the original total of mobs to the cl structure so we can * take care of the percentage damage decrease later * cl_targets+0 should point to the intended victim which should * either be from the invocation or from FIGHTING(ch) or from * whatever that function I wrote for berserk/etc is. */ ASPELL(spell_chain_lightning) { struct chain_lightning *cl; struct cl_targets *cl_targ; struct char_data *vict; struct char_data *next; EVENTFUNC(chain_lightning_event); if(ch->player_specials->saved.chain_lightning) { send_to_char(ch, "You can not cast this until the last one dissipates.\r\n"); return; } CREATE(cl_targ, struct cl_targets, 1); CREATE(cl, struct chain_lightning, 1); cl->caster = ch; cl->roomnum = IN_ROOM(ch); cl->hop = 1; cl->initial_dam = 300 + number(1, 100); cl->targets = cl_targ; /* * Start with the initial target. */ cl_targ->target = victim; CREATE(cl_targ->next, struct cl_targets, 1); cl_targ = cl_targ->next; act("$n creates a huge arc of lightning which leaps from $m to $N.", FALSE, ch, 0, victim, TO_BATTLE); act("You create a huge arc of lightning, directed at $N.", FALSE, ch, 0, victim, TO_CHAR); act("$n creates a huge arc of lighting, which leaps directly to YOU!", FALSE, ch, 0, victim, TO_VICT | TO_SLEEP); for(vict = world[IN_ROOM(ch)].people; vict; vict = next) { next = vict->next_in_room; if(vict == ch) continue; if(vict == victim) continue; if(!IS_NPC(vict)) continue; if(IS_NPC(vict) && IS_AFFECTED(vict, AFF_CHARM)) continue; cl_targ->target = vict; CREATE(cl_targ->next, struct cl_targets, 1); cl_targ = cl_targ->next; } ch->player_specials->saved.chain_lightning = event_create(chain_lightning_event, cl, PULSE_VIOLENCE / 2); } Put this one somewhere (I put it in events.c just to keep all my event routines together.) /* * Attempt #1 at a chain lightning event. * struct stores: * caster -> char_data of caster; * prev_vict -> the person the lightning will be jumping FROM. * initial_dam -> the initial damage done. * hop -> how many times it's jumped so far. * * I really really hate goto's, so this needs recoded better. * For now it works though. */ EVENTFUNC(chain_lightning_event) { struct chain_lightning *cl = (struct chain_lightning *) event_obj; struct char_data *caster = cl->caster; struct cl_targets *targets = cl->targets; int damage; struct char_data *victim = targets->target; char to_vict[80], to_pvict[80], to_room[80], to_caster[80]; loop: /* Called when we find a victim who is no longer in the same room */ victim = cl->targets->target; if(victim && (IN_ROOM(victim) != cl->roomnum)) { if(!cl->targets->next) goto cleanup; /* if only you knew how painful it is to type these */ cl->targets = cl->targets->next; goto loop; } else if(cl->targets->next) cl->targets = cl->targets->next; if(!victim) { goto cleanup; } /* * Lose 5% of inital damage with each hop * This don't work since I call mag_damage :-( * Eventually rewrite this so damage is decreased with each hop, by some * percent based on number of victims total and hit so far. */ damage = MAX(cl->initial_dam - ((cl->hop * 5) * cl->initial_dam) / 100, 1); if(cl->hop > 1) { sprintf(to_vict, "%s's chain lightning arcs from %s to you.", GET_NAME(caster), GET_NAME(cl->prev_vict)); sprintf(to_pvict, "%s's chain lightning leaps from you to %s.", GET_NAME(caster), GET_NAME(victim)); sprintf(to_room, "%s's chain lightning leaps from %s to %s.", GET_NAME(caster), GET_NAME(cl->prev_vict), GET_NAME(victim)); sprintf(to_caster, "Your chain lightning leaps from %s to %s.", GET_NAME(cl->prev_vict), GET_NAME(victim)); act(to_pvict, FALSE, cl->prev_vict, 0, 0, TO_CHAR); act(to_caster, FALSE, caster, 0, 0, TO_CHAR); act(to_vict, FALSE, cl->prev_vict, 0, 0, TO_VICT | TO_SLEEP); act(to_room, FALSE, caster, 0, victim, TO_ROOM); } mag_damage(GET_LEVEL(cl->caster), cl->caster, victim, SPELL_LIGHTNING_BOLT, GET_SAVE(victim, 0)); #ifdef DEBUG send_to_char(caster, "Chain lightning: hop: %d prev_victim=%s victim=%s damage=%d\n", cl->hop++, cl->prev_vict ? GET_NAME(cl->prev_vict) : "Nobody", GET_NAME(victim), damage); #endif cl->prev_vict = victim; cl->hop++; return (PULSE_VIOLENCE / 2); cleanup: act("Your chain lightning dissipates.", FALSE, caster, 0, 0, TO_CHAR); free(cl); caster->player_specials->saved.chain_lightning = NULL; return 0; } Add the structure definitions (I put 'em in events.h) /* * linked list of targets for chain lightning */ struct cl_targets { struct char_data *target; struct cl_targets *next; }; struct chain_lightning { struct char_data *caster; struct cl_targets *targets; struct char_data *prev_vict; room_rnum roomnum; int initial_dam; int hop; }; And add the event structure holder to char_data. I put this in as one of the spares in player_special_data_saved, but that probably isn't the best place, and definitely bad if you don't use ascii pfiles. (replace one of the spares with: struct event *chain_lightning; and finally in call_magic (spell_parser.c) add case SPELL_CHAIN_LIGHTNING: MANUAL_SPELL(spell_chain_lightning); break;