From: "Keith W. Jones" From: Hades Subject: Dragon breath special procs I played with adding dragon breath into my test MUD. These are the changes that I made. I have play-tested all of these. They work fine. The dragon_guard special is in the desert. It makes this MOB a lot tougher so players should probably be warned if you do this to them. I also changed the lines in lib/misc/messages concerning dragon breath. I don't remember the changes (but they weren't big so I didn't document them) but I think they were spelling and such. Small things when you look at the big picture. =============================================================================== = magic.c: Inside the switch(spellnum) in mag_damage(): /* Dragon "spells". I've made them all the same as a fireball spell */ case SPELL_FIRE_BREATH: case SPELL_GAS_BREATH: case SPELL_FROST_BREATH: case SPELL_ACID_BREATH: case SPELL_LIGHTNING_BREATH: dam = dice(11, 8) + 11; break; Inside the switch(spellnum) in mag_areas(): case SPELL_FIRE_BREATH: to_char = "You snort and fire shoots out of your nostrils!"; to_room = "$n snorts and a gout of fire shoots out of $s nostrils at you!"; break; case SPELL_GAS_BREATH: to_char = "You burp and a noxious gas rolls rapidly out of your nostrils!"; to_room = "$n rumbles and a noxious gas rolls out of $s nostrils!"; break; case SPELL_FROST_BREATH: to_char = "You shiver as a shaft of frost leaps from your mouth!"; to_room = "$n shivers as a shaft of frost leaps from $s mouth!"; break; case SPELL_ACID_BREATH: to_char = "Your indigestion acts up and a wash of acid leaps from your mout h!"; to_room = "$n looks pained as a wash of acid leaps from $s mouth!"; break; case SPELL_LIGHTNING_BREATH: to_char = "You open your mouth and bolts of lightning shoot out!"; to_room = "$n opens $s mouth and bolts of lightning shoot out!"; break; ------------------------------------------------------------------------------- - spec_assign.c: Inside assign_mobiles(), before assign_kings_castle() [personal preference] : SPECIAL(dragon_fire); SPECIAL(dragon_gas); SPECIAL(dragon_frost); SPECIAL(dragon_acid); SPECIAL(dragon_lightning); SPECIAL(dragon_guard); I removed the duplicate ASSIGNMOB() calls and added these: /* Some dragon breath mobiles */ /* Trials of Minos */ ASSIGNMOB(908, dragon_frost); /* dragon turtle */ /* The desert (this one is a change from guild_guard) */ ASSIGNMOB(5005, dragon_guard); /* brass dragon */ /* The forest of Haon-Dor (this one is a change from magic_user) */ ASSIGNMOB(6112, dragon_gas); /* green dragon */ /* Arachnos (this one is a change from magic_user) */ ASSIGNMOB(6302, dragon_acid); /* Yevaud */ /* The sewers */ ASSIGNMOB(7040, dragon_fire); /* red dragon */ ------------------------------------------------------------------------------- - spec_procs.c: After the "Special procedures for mobiles" comment: /* I can't find an example of a mobile casting an area spell so I'm going to * fake it using the magic user special. */ SPECIAL(dragon_fire) { struct char_data *dragon = (struct char_data *) me; /* I don't know what 'cmd' is but we never do anything if we don't breathe * fire unless we're fighting. */ if (cmd || GET_POS(ch) != POS_FIGHTING) return FALSE; /* Only breathe fire 20% of the time */ if (number(0, 4)) return FALSE; /* We could actually pass GET_LEVEL(ch) instead of 0 for the level of the * breath so we could have tougher dragons. Right now, it does damage * equal to a fireball in all cases. */ /* call_magic(ch, NULL, NULL, SPELL_FIRE_BREATH, 0, CAST_BREATH); */ damage(dragon, FIGHTING(dragon), , 0); /* If you use the damage call, you don't need the spell, but if you use * the spell, you should add the no_magic room information below. */ return TRUE; } SPECIAL(dragon_gas) { struct char_data *dragon = (struct char_data *) me; /* I don't know what 'cmd' is but we never do anything if we don't breathe * gas unless we're fighting. */ if (cmd || GET_POS(ch) != POS_FIGHTING) return FALSE; /* Only breathe gas 20% of the time */ if (number(0, 4)) return FALSE; /* We could actually pass GET_LEVEL(ch) instead of 0 for the level of the * breath so we could have tougher dragons. Right now, it does damage * equal to a fireball in all cases. */ /* call_magic(ch, NULL, NULL, SPELL_GAS_BREATH, 0, CAST_BREATH); */ damage(dragon, FIGHTING(dragon), , 0); /* If you use the damage call, you don't need the spell, but if you use * the spell, you should add the no_magic room information below. */ return TRUE; } SPECIAL(dragon_frost) { struct char_data *dragon = (struct char_data *) me; /* I don't know what 'cmd' is but we never do anything if we don't breathe * frost unless we're fighting. */ if (cmd || GET_POS(ch) != POS_FIGHTING) return FALSE; /* Only breathe frost 20% of the time */ if (number(0, 4)) return FALSE; /* We could actually pass GET_LEVEL(ch) instead of 0 for the level of the * breath so we could have tougher dragons. Right now, it does damage * equal to a fireball in all cases. */ /* call_magic(ch, NULL, NULL, SPELL_FROST_BREATH, 0, CAST_BREATH); */ damage(dragon, FIGHTING(dragon), , 0); /* If you use the damage call, you don't need the spell, but if you use * the spell, you should add the no_magic room information below. */ return TRUE; } SPECIAL(dragon_acid) { struct char_data *dragon = (struct char_data *) me; /* I don't know what 'cmd' is but we never do anything if we don't breathe * acid unless we're fighting. */ if (cmd || GET_POS(ch) != POS_FIGHTING) return FALSE; /* Only breathe acid 20% of the time */ if (number(0, 4)) return FALSE; /* We could actually pass GET_LEVEL(ch) instead of 0 for the level of the * breath so we could have tougher dragons. Right now, it does damage * equal to a fireball in all cases. */ /* call_magic(ch, NULL, NULL, SPELL_ACID_BREATH, 0, CAST_BREATH); */ damage(dragon, FIGHTING(dragon), , 0); /* If you use the damage call, you don't need the spell, but if you use * the spell, you should add the no_magic room information below. */ return TRUE; } SPECIAL(dragon_lightning) { struct char_data *dragon = (struct char_data *) me; /* I don't know what 'cmd' is but we never do anything if we don't breathe * lightning unless we're fighting. */ if (cmd || GET_POS(ch) != POS_FIGHTING) return FALSE; /* Only breathe lightning 20% of the time */ if (number(0, 4)) return FALSE; /* We could actually pass GET_LEVEL(ch) instead of 0 for the level of the * breath so we could have tougher dragons. Right now, it does damage * equal to a fireball in all cases. */ /* call_magic(ch, NULL, NULL, SPELL_LIGHTNING_BREATH, 0, CAST_BREATH); */ damage(dragon, FIGHTING(dragon), , 0); /* If you use the damage call, you don't need the spell, but if you use * the spell, you should add the no_magic room information below. */ } /* This is the special for the brass dragon in the desert */ SPECIAL(dragon_guard) { int i; extern int guild_info[][3]; struct char_data *dragon = (struct char_data *) me; char *buf = "The dragon growls at you, blocking your way.\r\n"; char *buf2 = "The dragon scares $n by growling fiercely, stopping $m in $s tr acks."; /* Check to see if a character is trying to move past the dragon */ if (IS_MOVE(cmd) && !IS_AFFECTED(dragon, AFF_BLIND)) { for (i = 0; guild_info[i][0] != -1; i++) { if ((IS_NPC(ch) || GET_CLASS(ch) != guild_info[i][0]) && world[ch->in_room].number == guild_info[i][1] && cmd == guild_info[i][2]) { send_to_char(buf, ch); act(buf2, FALSE, ch, 0, 0, TO_ROOM); return TRUE; } } } /* Nothing left to do except cast spells if we are fighting */ if (cmd || GET_POS(ch) != POS_FIGHTING) return FALSE; /* Only breathe lightning 20% of the time */ if (number(0, 4)) return FALSE; /* We could actually pass GET_LEVEL(ch) instead of 0 for the level of the * breath so we could have tougher dragons. Right now, it does damage * equal to a fireball in all cases. */ /* call_magic(ch, NULL, NULL, SPELL_LIGHTNING_BREATH, 0, CAST_BREATH); */ damage(dragon, FIGHTING(dragon), , 0); /* If you use the damage call, you don't need the spell, but if you use * the spell, you should add the no_magic room information below. */ return TRUE; } ------------------------------------------------------------------------------- - spell_parser.c: I figured a dragon's breath is not a spell, so if you use the spell method, you will need to add this: Within call_magic(), replacing the ROOM_FLAGGED...ROOM_NOMAGIC code: if (ROOM_FLAGGED(caster->in_room, ROOM_NOMAGIC)) { send_to_char("Your magic fizzles out and dies.\r\n", caster); act("$n's magic fizzles out and dies.", FALSE, caster, 0, 0, TO_ROOM); return 0; } /* I want dragons to be able to breathe fire in NOMAGIC areas because it * is more of an ability than a spell. Note: if the person using the * breath weapon is not an NPC, then the NOMAGIC affect still applies * because I don't have any PC's with breath capabilities. */ if (casttype != CAST_BREATH || (casttype == CAST_BREATH && !IS_NPC(caster))) { if (ROOM_FLAGGED(caster->in_room, ROOM_NOMAGIC)) { send_to_char("Your magic fizzles out and dies.\r\n", caster); act("$n's magic fizzles out and dies.", FALSE, caster, 0, 0, TO_ROOM); return 0; } } Inside mag_assign_spells(), after SPELL_IDENTIFY: /* Dragon breath */ spello(SPELL_FIRE_BREATH, 0, 0, 0, 0, 0, 0, 0, POS_FIGHTING, TAR_IGNORE, TRUE, MAG_AREAS); spello(SPELL_GAS_BREATH, 0, 0, 0, 0, 0, 0, 0, POS_FIGHTING, TAR_IGNORE, TRUE, MAG_AREAS); spello(SPELL_FROST_BREATH, 0, 0, 0, 0, 0, 0, 0, POS_FIGHTING, TAR_IGNORE, TRUE, MAG_AREAS); spello(SPELL_ACID_BREATH, 0, 0, 0, 0, 0, 0, 0, POS_FIGHTING, TAR_IGNORE, TRUE, MAG_AREAS); spello(SPELL_LIGHTNING_BREATH, 0, 0, 0, 0, 0, 0, 0, POS_FIGHTING, TAR_IGNORE, TRUE, MAG_AREAS); spells.h: In the CAST_* area: #define CAST_UNDEFINED -1 #define CAST_SPELL 0 #define CAST_POTION 1 #define CAST_WAND 2 #define CAST_STAFF 3 #define CAST_SCROLL 4 + #define CAST_BREATH 5 =============================================================================== = A word (or words even) of warning: I would have to consider myself to be a novice CircleMUD programmer but in the same breath, I would have to say that I'm a very good C programmer (a decade of experience should allow me to say that in all modesty) so that might make up the difference. Your opinion may differ after you've looked at my code. :) All in all, I found this change to be rather easy. I have to applaud Jeremy Elson for his code. It was very nice to work with. Nice internal documentation, easy to maintain, etc. I think the Circle mailing list should attempt to finish off Jeremy's coding.doc file. I think there should be enough knowledge here to allow us to do this. And it would probably help a lot of newbie imps like myself to avoid introducing bugs into the code. I hope this helps. Keith Jones keithjon@cuug.ab.ca