Blogs

On Vacation

My turn for a vacation, I'll be gone for one week. Checking in occasionally. As usual email myself and Welcor if there are any problems with the server or the game is down. Shamra is in charge with Fizban and Tink to back him up when he is not around. Have a good week everyone. tbaMUD 3.57 will be coming in August.

Difference between CircleMUD

This question came up again so here is an incomplete list of differences between stock CircleMUD 3.1 and tbaMUD 3.56:
ANSI Color
OasisOLC 2.0.6
trigedit (DG Scripts) 1.0.14
hedit (help editor)
cedit (config editor)
tedit (text file editor)
aedit (socials editor)
qedit (quest editor)
ASCII Player Files 3.0.1
128bit Support
Copyover
automap (ASCII map generator)
buildwalk (walk a new zone to link rooms)
tell m-w (an in game dictionary lookup)
gemote (emotes over gossip)
history (of all communications, tells, gossip, etc.)
file (allows imms to view syslog, errors, etc.)
pagelength (custom pagelength setting)
showvnums (previously roomflags)
zpurge (purge an entire zone)
zcheck (head builder tool to check balancing)
mob autoroll (standard values set on mob level entry)
checkload (
Auto Toggles
Hidden mob/obj
mob/obj stacking
hindex
helpcheck
mcopy/ocopy/rcopy/scopy/tcopy
export
(lots of major bugfixes too)

Creating Area Spells

Introduction

I wrote this guide to help people add in basic area spells. It is not meant to be a guide for advanced spells or any other type of spell. It is written, tested, and works on stock tbaMUD. It may or may not work if your game is heavily modified or from an older version of CWG.

The Code

*** In spells.h scroll down to the bottom of the spell list and define a 
*** new one. Make sure it is +1 from the previous spell.

  #define SPELL_WATERWALK              51 /* Reserved Skill[] DO NOT CHANGE */
  #define SPELL_METEOR                 52 /* Meteor of DOOM! */
+ #define SPELL_TREMOR                 53 /* A miniature Earthquake */


*** In spells.h, right under that, there should be #define NUM_SPELLS. Make
*** sure you add one to that since you have defined a new one.

+ #define NUM_SPELLS    53


*** In magic.c search Area Spells (commented out). You should see Earthquake,
*** which is a great example for an area spell. Tremor, the new spell, acts like 
*** Earthquake but only weaker.

     /* Area spells */
   case SPELL_EARTHQUAKE:
     dam = dice(2, 8) + level;
     break;

+  case SPELL_TREMOR:
+    dam = dice(1, 4) + level;
+    break;

**( In magic.c still, search for another instance of Earthquake. It will look 
*** something like below. Add in another case for the new area spell.

   switch (spellnum) {
   case SPELL_EARTHQUAKE:
     to_char = "You gesture and the earth begins to shake all around you!";
     to_room ="$n gracefully gestures and the earth begins to shake violently!";
     break;

+  case SPELL_TREMOR:
+    to_char = "You gesture and cause a tremor to shake the ground beneath you!";
+    to_room = "$n gracefully gestures, causing a tremor to shake the ground beneath you!";
+    break;
   }


*** In spell_parser.c search for Earthquake since it is an area spell.
*** It will be listed many lines below mag_assign_spells.
*** 40, 25, 3 in Earthquake stands for minimum mana cost of 25, maximum mana cost
*** of 40. Every level the mana cost decreases by 3 but it will never go
*** below 25. So in Tremor the new spell, I lowered the cost because it is weaker.

 
   spello(SPELL_EARTHQUAKE, "earthquake", 40, 25, 3, POS_FIGHTING,
         TAR_IGNORE, TRUE, MAG_AREAS,
         NULL);

+  spello(SPELL_TREMOR, "tremor", 30, 15, 2, POS_FIGHTING,
+        TAR_IGNORE, TRUE, MAG_AREAS,
+        NULL);


*** In class.c search for init_spell_levels and add in your new
*** spell into that list. CLASS_CLERIC can be any of the classes that
*** are built into your game. Level "8" is the level of which the Cleric
*** will learn Tremor.

   spell_level(SPELL_WORD_OF_RECALL, CLASS_CLERIC, 12);
   spell_level(SPELL_EARTHQUAKE, CLASS_CLERIC, 12);
+  spell_level(SPELL_TREMOR, CLASS_CLERIC, 8);
   spell_level(SPELL_DISPEL_EVIL, CLASS_CLERIC, 14);


*** Back out of the src directory, and enter the lib director, then
*** misc. Open the file messages, search for the damaging spells, and add
*** in the messages for your new spell. Be sure the number above the messages
*** match the spell number from spells.h. 
*** Note: Don't forget the "M" on the line just above the spell number!!!

+ * Tremor
+ M
+  53
+ A small crack opens beneath $N's feet and swallows $M whole!
+ A small crack opens beneath your feet and swallows you whole!
+ A small crack opens beneath $N's feet and swallows $M whole!
+ $N desperately tries to keep $S balance as the earth tremors beneath $S feet!
+ You desperately try to keep your balance as the earth tremors beneath your feet!
+ $N desperately tries to keep $S balance as the earth tremors beneath $S feet!
+ $N falls down and hurts $Mself!
+ You fall down and hurt yourself!
+ $N falls down and hurts $Mself!
+ $N holds $S ground as you send a tremor $S way.
+ You hold your ground as the tremor shakes the place.
+ $N holds $S ground as a tremor shakes the place.

Updated Fishing Snippet

Introduction

I was looking to add in fishing on the new AstoriaTBA port, to help bide some time with the conversion, so I Googled for some snippets.

I came up with an old snippet, which I've seen done on some other MUDs, and figured why not. The snippet I found and modified here.

I wrote this guide to help people add in basic fishing for players. It is not meant to be a guide for advanced fishing and I am not claiming the original idea for it, nor even the code. It is written, tested, and works on stock tbaMUD. It may or may not work if your game is heavily modified or from an older version of CWG.

FIXES

send_to_chars were backwards.
Example: send_to_char("You need to be holding a fishing pole first.\r\n", ch);
should be:
send_to_char(ch, "You need to be holding a fishing pole first.\r\n");

number should be rand_number
Example: bite = number(1, 10);
should be:
bite = rand_number(1, 10);

Changed sprintf to send_to_char
Example: sprintf(buf, "You reel in %s! Nice catch!\r\n", fish->short_description);
should be:
send_to_char(ch, "You reel in %s! Nice catch!\r\n", fish->short_description);

Added in some things to interpreter.c and act.h as well

So here it is, revised, with all of the fixes. (Much thanks go to Fizban for helping squash several of the errors. His scripting website is here if anyone has any script related questions.)

Fishing Snippet

*** In structs.h, with all your player flags, add this to the bottom.

    #define PLR_CRYO             15   /**< Player is cryo-saved (purge prog) */
    #define PLR_NOTDEADYET       16   /**< (R) Player being extracted        */
+   #define PLR_FISHING          17   /**< Player has a line in the water    */
+   #define PLR_FISH_ON          18   /**< Player has a fish on their line   */


*** In structs.h, with your item types, add this to the bottom.

  #define ITEM_FOUNTAIN     23               /**< Item is a fountain         */
+ #define ITEM_POLE         24               /**< Item is a fishing pole     */


*** Be sure to increase #define NUM_ITEM_TYPES by one.

+ #define NUM_ITEM_TYPES    25


*** In structs.h, with your flags, add this to the bottom. Be sure to
*** increase NUM_ROOM_FLAGS by one.

  #define ROOM_BFS_MARK            15   /**< (R) breath-first srch mrk */
  #define ROOM_WORLDMAP            16   /**< World-map style maps here */
+ #define ROOM_SALTWATER_FISH      17   /**< Fish are saltwater        */
+ #define ROOM_FRESHWATER_FISH     18   /**< Fish are freshwater       */


*** In constants.c, add to const char *room_bits[] at bottom,
*** before "\n".

   "WORLDMAP",
+  "SALTWATER_FISH",
+  "FRESHWATER_FISH",
  "\n"


*** In constants.c, add to const char *player_bits[] at bottom, 
*** before "\n"

   "UNUSED5",
+  "FISHING",
+  "FISH_ON",
   "\n"


*** In constants.c, add to const char *item_types[] at bottom,
*** before "\n"
   "FOUNTAIN",
+  "FISHING POLE",
   "\n"


*** In act.item.c add at the bottom.

 ACMD(do_castout)
 {
   struct obj_data *pole;
   int fail;
 
   if (PLR_FLAGGED(ch, PLR_FISHING)) {
     send_to_char(ch, "You are already fishing!\r\n");
     return;
   }
   if (!(pole = GET_EQ(ch, WEAR_HOLD)) ||
       (GET_OBJ_TYPE(pole) != ITEM_POLE)) {
     send_to_char(ch, "You need to be holding a fishing pole first.\r\n");
     return;
   }
   if (!ROOM_FLAGGED(ch->in_room, ROOM_SALTWATER_FISH) &&
       !ROOM_FLAGGED(ch->in_room, ROOM_FRESHWATER_FISH)) {
     send_to_char(ch, "This is not a good place to fish, you'll want to find a "
                      "better spot.\r\n");
     return;
   }
  fail = rand_number(1, 10);
   if (fail <= 3) {
    send_to_char(ch, "You pull your arm back and try to cast out your line, but "
                     "it gets all tangled up.\r\nTry again.\r\n");
     act("$n pulls $s arm back, trying to cast $s fishing line out into the "
         "water,\r\nbut ends up just a bit tangled.\r\n",
          FALSE, ch, 0, 0, TO_ROOM);
     return;
   }
   /* Ok, now they've gone through the checks, now set them fishing */
   SET_BIT_AR(PLR_FLAGS(ch), PLR_FISHING);
   send_to_char(ch, "You cast your line out into the water, hoping for a bite.\r\n");
   act("$n casts $s line out into the water, hoping to catch some food.\r\n",
        FALSE, ch, 0, 0, TO_ROOM);
   return;
 }
 
 ACMD(do_reelin)
 {
   int success, f_num, fish_num;
   struct obj_data *fish;
 
   if (!PLR_FLAGGED(ch, PLR_FISHING)) {
    send_to_char(ch, "You aren't even fishing!\r\n");
     return;
   }
   if (!PLR_FLAGGED(ch, PLR_FISH_ON)) {
    send_to_char(ch, "You reel in your line, but alas... nothing on the end.\r\n"
                     "Better luck next time.\r\n");
     REMOVE_BIT_AR(PLR_FLAGS(ch), PLR_FISHING);
     act("$n reels $s line in, but with nothing on the end.\r\n",
         FALSE, ch, 0, 0, TO_ROOM);
     return;
   }
 
   /* Ok, they are fishing and have a fish on */
   success = rand_number(1, 10);
 
   REMOVE_BIT_AR(PLR_FLAGS(ch), PLR_FISHING);
   REMOVE_BIT_AR(PLR_FLAGS(ch), PLR_FISH_ON);
 
   if (success <= 6) {
    send_to_char(ch, "You reel in your line, putting up a good fight, but you "
                     "lose him!\r\nTry again?\r\n");

     act("$n reels $s line in, fighting with whatever is on the end, but loses "
         "the catch.\r\n", FALSE, ch, 0, 0, TO_ROOM);
     return;
   }
 
   /* We used object vnums 10030-10050 for our fish that people could
    * catch. The below numbers reflect that use. If you wish to change
    * the vnums of the fish, just change the numbers below. You can
    * see that we seperated the type of fish by freshwater and salt
    * water.
    */
   if (ROOM_FLAGGED(ch->in_room, ROOM_SALTWATER_FISH)) {
     fish_num = rand_number(10030, 10039);
     f_num = real_object(fish_num);
     fish = read_object(f_num, REAL);
     send_to_char(ch, "You reel in %s! Nice catch!\r\n",fish->short_description);
     act("Wow! $n reels in a helluva catch! Looks like $p!\r\n",
         FALSE, ch, fish, 0, TO_ROOM);
     obj_to_char(fish, ch);
     return;
   } else
   if (ROOM_FLAGGED(ch->in_room, ROOM_FRESHWATER_FISH)) {
     fish_num = rand_number(10040, 10050);
     f_num = real_object(fish_num);
     fish = read_object(f_num, REAL);
    send_to_char(ch, "You reel in %s! Nice catch!\r\n", fish->short_description);
   act("Wow! $n reels in a helluva catch! Looks like a $p!\r\n",
       FALSE, ch, fish, 0, TO_ROOM);
     obj_to_char(fish, ch);
     return;
   } else
   send_to_char(ch, "You should never see this message, please report it.\r\n");
   return;
 }


*** Now, in comm.c add to your voids at the top of the file.

  void check_fishing();


*** In comm.c in, before PULSE_DG_SCRIPT, add:

   if (!(pulse % (40 * PASSES_PER_SEC)))
     check_fishing();


*** In weather.c at the bottom, add:

void check_fishing() {

  struct descriptor_data *d;
  int bite;

  for (d = descriptor_list; d; d = d->next) {
    if (d->connected) continue;

    if (PLR_FLAGGED(d->character, PLR_FISHING) &&
      (!ROOM_FLAGGED(d->character->in_room, ROOM_SALTWATER_FISH) &&
       !ROOM_FLAGGED(d->character->in_room, ROOM_FRESHWATER_FISH)))
      REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_FISHING);

    if (PLR_FLAGGED(d->character, PLR_FISHING) &&
       !PLR_FLAGGED(d->character, PLR_FISH_ON)) {

     bite = rand_number(1, 10);

      if (bite >= 7 && bite <= 8) {
       send_to_char(d->character, "Time goes by... not even a nibble.\r\n");
      } else if (bite >= 6) {
        send_to_char(d->character, "You feel a slight jiggle on your line.\r\n");
      } else if (bite >= 4) {
        send_to_char(d->character, "You feel a very solid pull on your line!\r\n");
       SET_BIT_AR(PLR_FLAGS(d->character), PLR_FISH_ON);
      } else if (bite >= 2) {
        send_to_char(d->character, "Your line suddenly jumps to life, FISH ON!!!\r\n");
       SET_BIT_AR(PLR_FLAGS(d->character), PLR_FISH_ON);
      }
    }
  }
}


*** In act.movement.c, in do_simple_move add the below snippet just 
*** above char_from_room:

  if ((ROOM_FLAGGED(ch->in_room, ROOM_SALTWATER_FISH) ||
       ROOM_FLAGGED(ch->in_room, ROOM_FRESHWATER_FISH)) &&
      (PLR_FLAGGED(ch, PLR_FISHING) || PLR_FLAGGED(ch, PLR_FISH_ON))) {
    REMOVE_BIT_AR(PLR_FLAGS(ch), PLR_FISHING);
    REMOVE_BIT_AR(PLR_FLAGS(ch), PLR_FISH_ON);
    send_to_char(ch, "\r\nYou pack up your fishing gear and move on.\r\n\r\n");
  }


*** In fight.c in void damage, just under the Sanctuary check, add:

   /* Cut damage in half if victim has sanct, to a minimum 1 */
   if (AFF_FLAGGED(victim, AFF_SANCTUARY) && dam >= 2)
     dam /= 2;
 
  /* Player Fishing */
+    if (PLR_FLAGGED(victim, PLR_FISHING) && dam >= 4)
+        dam = ((float) dam * 1.5);


*** New: In interpreter.c under "cast" add:

   { "cast"     , "c"       , POS_SITTING , do_cast     , 1, 0 },
+  { "castout"  , "castout" , POS_SITTING , do_castout  , 0, 0 },


*** New! In interpreter.c under "receive" add:

   { "receive"  , "rece"    , POS_STANDING, do_not_here , 1, 0 },
+  { "reelin"   , "reelin"  , POS_SITTING , do_reelin   , 0, 0 },


*** New! In act.h add this below the other ACMD's of functions without subcommands:

    ACMD(do_rescue);
    /* Fishing */
+ ACMD(do_castout);
+ ACMD(do_reelin);


Fishing Help File

FISHING CASTOUT REELIN

Usage: castout
reelin

To fish, you must be near water, in a room specified as such. Also, you
must be holding a fishing pole. If you move from your original place of
fishing, you automatically pack up your gear and move on.

Anyone can fish, all you need is a fishing pole and patience.

Note: If you are fishing and get attacked, your fighting skills are
severely impeded, and you will take more than your average
damage until you reel your line in.

Happy fishing everyone!

Creating Damaging Spells

Introduction

I wrote this guide to help people add in basic damaging spells. It is not meant to be a guide for advanced spells or any other type of spell. It is written, tested, and works on stock tbaMUD. It may or may not work if your game is heavily modified or from an older version of CWG.

The Code

*** In spells.h scroll down to the bottom of the spell list and define a 
*** new one. Make sure it is +1 from the previous spell.

  #define SPELL_INFRAVISION            50 /* Reserved Skill[] DO NOT CHANGE */
  #define SPELL_WATERWALK              51 /* Reserved Skill[] DO NOT CHANGE */
+ #define SPELL_METEOR                 52 /* Meteor of DOOM! */


*** In spells.h, right under that, there should be #define NUM_SPELLS. Make
*** sure you add one to that since you have defined a new one.

+ #define NUM_SPELLS    52


*** In magic.c search mag_damage and scroll past the spellnum. 
*** The spells here should be damaging spells like Fireball, Magic Missile,
*** and Chill Touch. Add in the new spell beneath it.
*** Note: If the spell affects the character casting in any way it must be 
*** added to man_damage (with spells like Armor and Blindness) but in this
*** example the spell does not.

   case SPELL_FIREBALL:
    if (IS_MAGIC_USER(ch))
      dam = dice(11, 8) + 11;
    else
      dam = dice(11, 6) + 11;
    break;
+   case SPELL_METEOR:
+   dam = dice(25, 15) + 15;
+   break;


*** In spell_parser.c search for another damaging spell. I used Fireball as
*** my template. These spells should be listed a few lines below 
*** mag_assign_spells.
 
    spello(SPELL_FIREBALL, "fireball", 40, 30, 2, POS_FIGHTING,
          TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE,
          NULL);

+   spello(SPELL_METEOR, "meteor", 40, 30, 2, POS_FIGHTING,
+         TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE,
+         NULL);


*** In class.c search for init_spell_levels and add in your new
*** spell into that list. CLASS_MAGIC_USER can be any of the classes that
*** are built into your game, but since Mages are the unpredictable spell
*** casters I chose to assign it to them. "30" is the level of which the Mage
*** will learn that spell.

   spell_level(SPELL_FIREBALL, CLASS_MAGIC_USER, 15);
+  spell_level(SPELL_METEOR, CLASS_MAGIC_USER, 30);
   spell_level(SPELL_CHARM, CLASS_MAGIC_USER, 16);


*** Back out of the src directory, and enter the lib director, then
*** misc. Open the file messages, search for the damaging spells, and add
*** in the messages for your new spell. Be sure the number above the messages
*** match the spell number from spells.h. 
*** Note: Don't forget the "M" on the line just above the spell number!!!

+ * Meteor
+ M
+  52
+ Your meteor hits $N with full force, causing an immediate death!
+ A meteor summoned by $n hits you with full force. What a way to go...
+ $N summons a meteor on $n's head, causing instant death. Booyah!
+ The meteor you summoned seems to have...disintegrated.
+ The meteor $n summoned seems to have disintegrated. Whew!
+ The meteor $n summoned upon $N's head seems to have disintegrated. Oops!
+ You summon a meteor from the sky and reign it down upon the doomed head of $N!
+ $n has summoned a flaming meteor down upon your head. Ping!
+ $N has summoned a flaming meteor from the sky upon the doomed head of $N!
+ Hah, the Gods -made- the meteors!
+ Laugh, $n has tried summoning a meteor to hit you!
+ $N gracefully disintegrates the meteor that $n has tried to summon.

New lib/messages

Thanks to Tink from Astoria for pointing out that spell messages were not working properly. Corrected messages file attached below. It turns out I did a find and replace (sed) to get rid of several ^M's leftover from MSDOS formatting. It also stripped the required M prior to every block of messages.

tbaMUD MUD's

I just wanted to take the time to welcome Astoria on to the tbaMUD band wagon. Jamdog is a major contributor to the tbaMUD codebase. Tink and Detta have been helping builders for years on TBA. I am looking forward to our continued joint ventures!

tbaMUD's:
The Builder Academy
Astoria
CrackWhip
Paragon
AderonMud
Azereth
Dragonball Fate
Smallville Untold Stories
Dragonball Awakening
Sermon MUD
Twilight's Failings

Let me know what tbaMUD's I missed.

tbaMUD codebase on TMC

The Mudconnector recently added the tbaMUD codebase to its list of MUD codebases. Those of you using tbaMUD can now update your TMC listing to show the proper codebase.

Expanding directions - Ordinal

Jamdog added an excellent patch here for those wanting to add more directions to tbaMUD.
http://cwg.lazuras.org/modules.php?name=Forums&file=viewtopic&t=2108

SVN write access

I have granted SVN write access to a select few trusted individuals and wish to post the ground rules here so there is no confusion about what is to be expected.

First we have standardized our commenting and format of files per Jeremy's post so please follow them:
http://www.tbamud.com/content/source-code-documentation-project

To checkout the SVN:
svn checkout http://tbamud.com/svn/circlemud/circlemud tbamud

When ready to make a change to the codebase always do an "svn update" prior to your modifications and to decrease the possibilities of conflicts run an "svn commit """ or "svn commit --file " as soon after as possible. Now any change you make in game be sure to test and then comment the details in the changelog via the in game command "changelog " then copy and paste the same text into a commit or a file to commit. All changes must be described in detail to prevent confusion. I will be checking all changes by looking at the different revisions. i.e. "svn diff -96:97" to see what was done.

If there are any questions don't hesitate to ask. The great part about SVN is we can easily track all changes and revert them if necessary.

If you have already contributed heavily to tbaMUD and desire SVN access please contact me on TBA.

Syndicate content