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!