I was able to successfully add fishing to my game using the snippet found here - 
How do I take this code a step further and only allow castout command to work if there is a 'school of fish' object that is randomly generated within the room that has the fishing flag on it?
I don't want players to be able to just cram into the nearest fishing flagged to town and just sit there fishing all day. I want to force exploration meaning they have to roam around the ocean or rivers looking for the school of fish object to fish from. I want this school of fish object to randomly generate or self destruct in random rooms every few ticks.
Hopefully that makes sense.
Code:
ACMD(do_castout)
{
  struct obj_data *pole;
  int fail;
  if (!can_see_room(ch, IN_ROOM(ch))) {
      send_to_char(ch, "It's too dark for you to castout here!\r\n");
      return;
    }
  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(IN_ROOM(ch), ROOM_SALTWATER_FISH) && !ROOM_FLAGGED(IN_ROOM(ch), 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, but ends up just a bit tangled.", 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.", FALSE, ch, 0, 0, TO_ROOM);
  return;
}
ACMD(do_reelin)
{
  int success, f_num, fish_num;
  struct obj_data *fish;
  char buf[MAX_STRING_LENGTH];
  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\nBetter 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.", 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 it!\r\nTry again?\r\n");
    act("$n reels $s line in, fighting with whatever is on the end, but loses the catch.", FALSE, ch, 0, 0, TO_ROOM);
    return;
  }
  /* We used object vnums 300 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(IN_ROOM(ch), ROOM_SALTWATER_FISH)) {
    fish_num = rand_number(114,116);
    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);
    obj_to_char(fish, ch);
    act("Wow! $n reels in a nice catch! Looks like $p!", FALSE, ch, fish, 0, TO_ROOM);
    return;
  } else
  if (ROOM_FLAGGED(IN_ROOM(ch), ROOM_FRESHWATER_FISH)) {
    fish_num = rand_number(300,306);
    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);
    obj_to_char(fish, ch);
    act("Wow! $n reels in a nice catch! Looks like $p!", FALSE, ch, fish, 0, TO_ROOM);
    return;
  } else
  send_to_char(ch, "You should never see this message, please report it.\r\n");
  return;
}