Dragon breath special procs

From: Keith W. Jones (keithjon@cuug.ab.ca)
Date: 12/04/95


This is in response to sonny@ursus.bke.hu but I thought more people could
benefit from it so I'm posting it to the mailing list.  He'd asked if anyone
had implemented dragon breath special procs and cleric procs.  I haven't done a
special for clerics but I did play with dragon breath the other day.  Here's
what I did (I hope everyone can follow it):

-------- cut here ---------------- cut here ---------------- cut here --------

I played with adding dragon breath into my test MUD.  These are the changes
that I made.  I used an "#ifdef ORIGINAL" around all my changes so that I
could remove them if something bad happened.

I have play-tested all of these.  They work fine.  The dragon_guard special is
in the desert.  Play testing this MOB also made me change the ROOM_NOMAGIC
test in spell_parser.c:call_magic() to allow dragon breath in such a room.  I
figured a dragon should be able to breathe when the room has no magic.  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 (I couldn't use "#ifdef ORIGINAL" in there and
the changes 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():

	#ifndef	ORIGINAL
	  /* 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;
	#endif

    Inside the switch(spellnum) in mag_areas():

	#ifndef	ORIGINAL
	  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 mouth!";
	    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;
	#endif
--------------------------------------------------------------------------------
spec_assign.c:

    Inside assign_mobiles(), before assign_kings_castle() [personal preference]:

	#ifndef	ORIGINAL
	  SPECIAL(dragon_fire);
	  SPECIAL(dragon_gas);
	  SPECIAL(dragon_frost);
	  SPECIAL(dragon_acid);
	  SPECIAL(dragon_lightning);
	  SPECIAL(dragon_guard);
	#endif

    I removed the duplicate ASSIGNMOB() calls and added these:

	#ifndef	ORIGINAL
	  /* 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 */
	#endif
--------------------------------------------------------------------------------
spec_procs.c:

    After the "Special procedures for mobiles" comment:

	#ifndef	ORIGINAL
	/* 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)
	{
	  /* 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 TRUE;

	  /* 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);
	  return TRUE;
	}

	SPECIAL(dragon_gas)
	{
	  /* 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 TRUE;

	  /* 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);
	  return TRUE;
	}

	SPECIAL(dragon_frost)
	{
	  /* 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 TRUE;

	  /* 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);
	  return TRUE;
	}

	SPECIAL(dragon_acid)
	{
	  /* 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 TRUE;

	  /* 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);
	  return TRUE;
	}

	SPECIAL(dragon_lightning)
	{
	  /* 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 TRUE;

	  /* 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);
	  return TRUE;
	}

	/* 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 tracks.";

	  /* 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 TRUE;

	  /* 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);
	  return TRUE;
	}
	#endif
--------------------------------------------------------------------------------
spell_parser.c:

    I figured a dragon's breath is not a spell.  You may not have this opinion
    so you're free to change it.

    Within call_magic(), replacing the ROOM_FLAGGED...ROOM_NOMAGIC code:

	#ifdef	ORIGINAL
	  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;
	  }
	#else
	  /* 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;
	    }
	  }
	#endif

    Inside mag_assign_spells(), after SPELL_IDENTIFY:

	#ifndef	ORIGINAL
	  /* 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);
	#endif


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
+	#ifndef	ORIGINAL
+	#define CAST_BREATH	5
+	#endif
================================================================================

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



This archive was generated by hypermail 2b30 : 12/07/00 PST