Ejemplo n.º 1
0
/* this function takes a real number for a room and returns:
   FALSE - mortals shouldn't be able to teleport to this destination 
   TRUE - mortals CAN teleport to this destination 
 * accepts NULL ch data
 */
int valid_mortal_tele_dest(struct char_data *ch, room_rnum dest, bool dim_lock) {

  if (dest == NOWHERE)
    return FALSE;

  if (IS_AFFECTED(ch, AFF_DIM_LOCK) && dim_lock)
    return FALSE;
  
  /* this function needs a vnum, not rnum */
  if (ch && !House_can_enter(ch, GET_ROOM_VNUM(dest)))
    return FALSE;

  if (ZONE_FLAGGED(GET_ROOM_ZONE(dest), ZONE_NOASTRAL))
    return FALSE;

  if (ROOM_FLAGGED(dest, ROOM_PRIVATE))
    return FALSE;

  if (ROOM_FLAGGED(dest, ROOM_DEATH))
    return FALSE;

  if (ROOM_FLAGGED(dest, ROOM_GODROOM))
    return FALSE;

  if (ZONE_FLAGGED(GET_ROOM_ZONE(dest), ZONE_CLOSED))
    return FALSE;

  if (ZONE_FLAGGED(GET_ROOM_ZONE(dest), ZONE_NOASTRAL))
    return FALSE;

  //passed all tests!
  return TRUE;
}
Ejemplo n.º 2
0
/* nb, also mess up anyone affected by AFF_POISON */
void pulse_heal(void)
{
    CharData *ch;
    int gain = number(18,24);

    for (ch = character_list; ch; ch = ch->next) {
        if(ch->in_room == NOWHERE)
            continue;

        if(!(pvpFactor() > 1)) {
            if( GET_POS(ch) == POS_INCAP )      damage(ch, ch, 1, TYPE_SUFFERING);
            else if( GET_POS(ch) == POS_MORTALLYW )  damage(ch, ch, 2, TYPE_SUFFERING);
            else if( GET_POS(ch) == POS_DEAD) {
                if(IN_ARENA(ch) || IN_QUEST_FIELD(ch) ||
                   ZONE_FLAGGED(world[ch->in_room].zone, ZONE_ARENA) ||
                   ZONE_FLAGGED(world[ch->in_room].zone, ZONE_SLEEPTAG))
                    // If they're dying in the arena, they eventually get better (or killed by someone)
                {
                    GET_HIT(ch) = number(GET_HIT(ch), 1);
                    sendChar(ch, "You slowly recover.\r\n");
                    update_pos(ch);
                }
                else {
                    raw_kill(ch, NULL);
                    continue;
                }
            }
        }

        if (IS_AFFECTED(ch, AFF_PULSE_HIT))
            if (GET_HIT(ch) < GET_MAX_HIT(ch)) GET_HIT(ch) += gain;
        if (IS_AFFECTED(ch, AFF_PULSE_MANA))
            if (GET_MANA(ch) < GET_MAX_MANA(ch)) GET_MANA(ch) += gain;
        if (IS_AFFECTED(ch, AFF_POISON)) doPoison(ch);
        if (IS_AFFECTED(ch, AFF_DISEASE)) doDisease(ch);
	if (affected_by_spell(ch, SKILL_INVIGORATE)) doInvigorate(ch);
        if (IS_BOUNTY_HUNTER(ch) && GET_ADVANCE_LEVEL(ch) >= 1 && IS_AFFECTED(ch, AFF_HIDE)) GET_MOVE(ch) = MIN(GET_MOVE(ch) + 3*gain, GET_MAX_MOVE(ch));
        if (IS_PRESTIDIGITATOR(ch)) GET_MANA(ch) = MIN(GET_MANA(ch) + GET_ADVANCE_LEVEL(ch) * 2, GET_MAX_MANA(ch));
        if (affected_by_spell(ch, SPELL_HIPPOCRATIC_OATH)) GET_MANA(ch) = MIN(GET_MANA(ch) + 25, GET_MAX_MANA(ch));
        if (affected_by_spell(ch, SKILL_PET_MEND)) GET_HIT(ch) = MIN(GET_HIT(ch) * 115 / 100, GET_MAX_HIT(ch));
        if (IS_HOLY_PRIEST(ch)) GET_MANA(ch) = MIN(GET_MANA(ch) + 10 + 2*GET_ADVANCE_LEVEL(ch), GET_MAX_MANA(ch));

        /* The room might be poisoned! (Or later, otherwise dangerous) */
        if (ch->in_room != NOWHERE) {
            if (ROOM_FLAGGED(ch->in_room, ROOM_POISONED)) {
                if (!mag_savingthrow(ch, SAVING_SPELL)) {
                    act("$n chokes and gags!", TRUE, ch, 0, 0, TO_ROOM);
                    act("You choke and gag!", TRUE, ch, 0, 0, TO_CHAR);
                    add_affect( ch, ch, SPELL_POISON, 30, APPLY_NONE, 0, 5 TICKS,
                            AFF_POISON, FALSE, FALSE, FALSE, FALSE);
                }
            }
        }

        if(IS_DEFENDER(ch) && !affected_by_spell(ch, SKILL_DEFENDER_HEALTH))
            add_affect(ch, ch, SKILL_DEFENDER_HEALTH, GET_LEVEL(ch), APPLY_HIT, GET_ADVANCE_LEVEL(ch)*5, -1, FALSE, FALSE, FALSE, FALSE, FALSE);

    }
}
Ejemplo n.º 3
0
bool show_worldmap(struct char_data *ch) {
  room_rnum rm = IN_ROOM(ch);
  zone_rnum zn = GET_ROOM_ZONE(rm);

  if (ROOM_FLAGGED(rm, ROOM_WORLDMAP)) return TRUE;
  if (ZONE_FLAGGED(zn, ZONE_WORLDMAP)) return TRUE;

  return FALSE;
}
Ejemplo n.º 4
0
/* Checks to see if a builder can modify the specified zone. Ch is the imm
 * requesting access to modify this zone. Rnum is the real number of the zone
 * attempted to be modified. Returns TRUE if the builder has access, otherwisei
 * FALSE. */
int can_edit_zone(struct char_data *ch, zone_rnum rnum)
{
  /* no access if called with bad arguments */
  if (!ch->desc || IS_NPC(ch) || rnum == NOWHERE)
    return FALSE;

  /* If zone is flagged NOBUILD, then No-one can edit it (use zunlock to open it) */
  if (rnum != HEDIT_PERMISSION && rnum != AEDIT_PERMISSION && ZONE_FLAGGED(rnum, ZONE_NOBUILD) )
    return FALSE;

  if (GET_OLC_ZONE(ch) == ALL_PERMISSION)
    return TRUE;

  if (GET_OLC_ZONE(ch) == HEDIT_PERMISSION && rnum == HEDIT_PERMISSION)
    return TRUE;

  if (GET_OLC_ZONE(ch) == AEDIT_PERMISSION && rnum == AEDIT_PERMISSION)
    return TRUE;

  /* always access if ch is high enough level */
  if (GET_ADMLEVEL(ch) >= ADMLVL_GRGOD)
    return (TRUE);

  /* always access if a player helped build the zone in the first place */
  if (rnum != HEDIT_PERMISSION && rnum != AEDIT_PERMISSION)
    if (is_name(GET_NAME(ch), zone_table[rnum].builders))
      return (TRUE);

  /* no access if you haven't been assigned a zone */
  if (GET_OLC_ZONE(ch) == NOWHERE) {
    return FALSE;
  }

  /* no access if you're not at least LVL_BUILDER */
  if (GET_ADMLEVEL(ch) < ADMLVL_BUILDER)
    return FALSE;

  /* always access if you're assigned to this zone */
  if (real_zone(GET_OLC_ZONE(ch)) == rnum)
    return TRUE;

  return (FALSE);
}
Ejemplo n.º 5
0
void gain_exp_unchecked(CharData *ch, int gain)
{
    // PC mobs do NOT gain exps at all.
    if (IS_AFFECTED(ch, AFF_CHARM) || MOB_FLAGGED(ch, MOB_CONJURED))
        return;
 
    // stop xps clocking over.
    if ((GET_EXP(ch) > 2000000000) && gain > 0)
        return;

    if (!IS_NPC(ch) && ((GET_LEVEL(ch) < 1 || GET_LEVEL(ch) > MAX_MORTAL)))
        return;

    if (IN_ARENA(ch)) return;
    if (ZONE_FLAGGED(world[ch->in_room].zone, ZONE_ARENA)) return;
    if (ZONE_FLAGGED(world[ch->in_room].zone, ZONE_SLEEPTAG)) return;

    /* NPCs just get their exp mod and leave */
    if (IS_NPC(ch)) {
        GET_EXP(ch) += gain;
        return;
    }

    if (gain > 0) {
        if ((GET_EXP(ch) + gain ) > INT_MAX)
            return;

        GET_EXP(ch) += gain;

        /* Did the player just earn a level? */
        if( GET_LEVEL(ch) < MAX_MORTAL &&
           GET_EXP(ch) >= titles[(int) GET_CLASS(ch)][GET_LEVEL(ch) + 1].exp)
        {
            send_to_char("You rise a level!\r\n", ch);
            GET_EXP(ch) = titles[(int) GET_CLASS(ch)][GET_LEVEL(ch) + 1].exp;
            GET_LEVEL(ch) += 1;
            level_up(ch);
            set_title(ch, NULL);
        }
    } else if (gain < 0) {
        long thisLvl = (titles[(int) GET_CLASS(ch)][GET_LEVEL(ch) + 0].exp);
        long nextLvl = (titles[(int) GET_CLASS(ch)][GET_LEVEL(ch) + 1].exp);
        long neg100 = thisLvl - nextLvl + thisLvl;

        GET_EXP(ch) += gain;

        /* uh oh spaghettios! */
        if (GET_EXP(ch) < 0 && IS_MORTAL(ch)) {
            mudlog(NRM, LVL_IMMORT, TRUE, "SOUL DEATH: %s reduced to 0 xps by death, deleting!",
                    GET_NAME(ch));   
            sendChar(ch, "Your soul is too weak to return to the world...");
            sendChar(ch, "Utter darkness surrounds you as you slowly slip "
                         "into oblivion...");
            act("A look of utter despair crosses $n's face as their very soul"
                " is destroyed.", TRUE, ch, 0, 0, TO_ROOM );
            SET_BIT_AR(PLR_FLAGS(ch), PLR_DELETED);
            if (ch->desc) SET_DCPENDING(ch->desc);
        }

        /* Did the player just lose a level? */
        if (GET_LEVEL(ch) > 1 && IS_MORTAL(ch) && GET_EXP(ch) <= neg100) {
            send_to_char("You have lost a level!\r\n", ch);
            GET_LEVEL(ch) -= 1;
            retreat_level(ch);
            set_title(ch, NULL);

            /* make sure they don't drop below 0% at their new level */
            if (GET_EXP(ch) < titles[(int)GET_CLASS(ch)][GET_LEVEL(ch)].exp)
                GET_EXP(ch) = titles[(int)GET_CLASS(ch)][GET_LEVEL(ch)].exp;
        }
    }
}
Ejemplo n.º 6
0
/** Move a PC/NPC character from their current location to a new location. This
 * is the standard movement locomotion function that all normal walking
 * movement by characters should be sent through. This function also defines
 * the move cost of normal locomotion as:
 * ( (move cost for source room) + (move cost for destination) ) / 2
 *
 * @pre Function assumes that ch has no master controlling character, that
 * ch has no followers (in other words followers won't be moved by this
 * function) and that the direction traveled in is one of the valid, enumerated
 * direction.
 * @param ch The character structure to attempt to move.
 * @param dir The defined direction (NORTH, SOUTH, etc...) to attempt to
 * move into.
 * @param need_specials_check If TRUE will cause
 * @retval int 1 for a successful move (ch is now in a new location)
 * or 0 for a failed move (ch is still in the original location). */
int do_simple_move(struct char_data *ch, int dir, int need_specials_check)
{
  /* Begin Local variable definitions */
  /*---------------------------------------------------------------------*/
  /* Used in our special proc check. By default, we pass a NULL argument
   * when checking for specials */
  char spec_proc_args[MAX_INPUT_LENGTH] = "";
  /* The room the character is currently in and will move from... */
  room_rnum was_in = IN_ROOM(ch);
  /* ... and the room the character will move into. */
  room_rnum going_to = EXIT(ch, dir)->to_room;
  /* How many movement points are required to travel from was_in to going_to.
   * We redefine this later when we need it. */
  int need_movement = 0;
  /* Contains the "leave" message to display to the was_in room. */
  char leave_message[SMALL_BUFSIZE];
  /*---------------------------------------------------------------------*/
  /* End Local variable definitions */


  /* Begin checks that can prevent a character from leaving the was_in room. */
  /* Future checks should be implemented within this section and return 0.   */
  /*---------------------------------------------------------------------*/
  /* Check for special routines that might activate because of the move and
   * also might prevent the movement. Special requires commands, so we pass
   * in the "command" equivalent of the direction (ie. North is '1' in the
   * command list, but NORTH is defined as '0').
   * Note -- only check if following; this avoids 'double spec-proc' bug */
  if (need_specials_check && special(ch, dir + 1, spec_proc_args))
    return 0;

  /* Leave Trigger Checks: Does a leave trigger block exit from the room? */
  if (!leave_mtrigger(ch, dir) || IN_ROOM(ch) != was_in) /* prevent teleport crashes */
    return 0;
  if (!leave_wtrigger(&world[IN_ROOM(ch)], ch, dir) || IN_ROOM(ch) != was_in) /* prevent teleport crashes */
    return 0;
  if (!leave_otrigger(&world[IN_ROOM(ch)], ch, dir) || IN_ROOM(ch) != was_in) /* prevent teleport crashes */
    return 0;

  /* Charm effect: Does it override the movement? */
  if (AFF_FLAGGED(ch, AFF_CHARM) && ch->master && was_in == IN_ROOM(ch->master))
  {
    send_to_char(ch, "The thought of leaving your master makes you weep.\r\n");
    act("$n bursts into tears.", FALSE, ch, 0, 0, TO_ROOM);
    return (0);
  }

  /* Water, No Swimming Rooms: Does the deep water prevent movement? */
  if ((SECT(was_in) == SECT_WATER_NOSWIM) ||
      (SECT(going_to) == SECT_WATER_NOSWIM))
  {
    if (!has_boat(ch))
    {
      send_to_char(ch, "You need a boat to go there.\r\n");
      return (0);
    }
  }

  /* Flying Required: Does lack of flying prevent movement? */
  if ((SECT(was_in) == SECT_FLYING) || (SECT(going_to) == SECT_FLYING))
  {
    if (!has_flight(ch))
    {
      send_to_char(ch, "You need to be flying to go there!\r\n");
      return (0);
    }
  }

  /* Underwater Room: Does lack of underwater breathing prevent movement? */
  if ((SECT(was_in) == SECT_UNDERWATER) || (SECT(going_to) == SECT_UNDERWATER))
  {
    if (!has_scuba(ch) && !IS_NPC(ch) && !PRF_FLAGGED(ch, PRF_NOHASSLE)) {
      send_to_char(ch, "You need to be able to breathe water to go there!\r\n");
      return (0);
    }
  }

  /* Houses: Can the player walk into the house? */
  if (ROOM_FLAGGED(was_in, ROOM_ATRIUM))
  {
    if (!House_can_enter(ch, GET_ROOM_VNUM(going_to)))
    {
      send_to_char(ch, "That's private property -- no trespassing!\r\n");
      return (0);
    }
  }

  /* Check zone level recommendations */
  if ((ZONE_MINLVL(GET_ROOM_ZONE(going_to)) != -1) && ZONE_MINLVL(GET_ROOM_ZONE(going_to)) > GET_LEVEL(ch)) {
    send_to_char(ch, "This zone is above your recommended level.\r\n");
  }

  /* Check zone flag restrictions */
  if (ZONE_FLAGGED(GET_ROOM_ZONE(going_to), ZONE_CLOSED)) {
    send_to_char(ch, "A mysterious barrier forces you back! That area is off-limits.\r\n");
    return (0);
  }
  if (ZONE_FLAGGED(GET_ROOM_ZONE(going_to), ZONE_NOIMMORT) && (GET_ADMLEVEL(ch) >= ADMLVL_IMMORT) && (GET_ADMLEVEL(ch) < ADMLVL_GRGOD)) {
    send_to_char(ch, "A mysterious barrier forces you back! That area is off-limits.\r\n");
    return (0);
  }

  /* Room Size Capacity: Is the room full of people already? */
  if (ROOM_FLAGGED(going_to, ROOM_TUNNEL) &&
      num_pc_in_room(&(world[going_to])) >= CONFIG_TUNNEL_SIZE)
  {
    if (CONFIG_TUNNEL_SIZE > 1)
      send_to_char(ch, "There isn't enough room for you to go there!\r\n");
    else
      send_to_char(ch, "There isn't enough room there for more than one person!\r\n");
    return (0);
  }

  /* Room Level Requirements: Is ch privileged enough to enter the room? */
  if (ROOM_FLAGGED(going_to, ROOM_GODROOM) && GET_ADMLEVEL(ch) < ADMLVL_GOD)
  {
    send_to_char(ch, "You aren't godly enough to use that room!\r\n");
    return (0);
  }

  /* All checks passed, nothing will prevent movement now other than lack of
   * move points. */
  /* move points needed is avg. move loss for src and destination sect type */
  need_movement = (movement_loss[SECT(was_in)] +
		   movement_loss[SECT(going_to)]) / 2;

  /* Move Point Requirement Check */
  if (GET_MOVE(ch) < need_movement && !IS_NPC(ch))
  {
    if (need_specials_check && ch->master)
      send_to_char(ch, "You are too exhausted to follow.\r\n");
    else
      send_to_char(ch, "You are too exhausted.\r\n");

    return (0);
  }

  /*---------------------------------------------------------------------*/
  /* End checks that can prevent a character from leaving the was_in room. */


  /* Begin: the leave operation. */
  /*---------------------------------------------------------------------*/
  /* If applicable, subtract movement cost. */
  if (GET_ADMLEVEL(ch) < ADMLVL_IMMORT && !IS_NPC(ch))
    GET_MOVE(ch) -= need_movement;

  /* Generate the leave message and display to others in the was_in room. */
  if (!AFF_FLAGGED(ch, AFF_SNEAK))
  {
    snprintf(leave_message, sizeof(leave_message), "$n leaves %s.", dirs[dir]);
    act(leave_message, TRUE, ch, 0, 0, TO_ROOM);
  }

  char_from_room(ch);
  char_to_room(ch, going_to);
  /*---------------------------------------------------------------------*/
  /* End: the leave operation. The character is now in the new room. */


  /* Begin: Post-move operations. */
  /*---------------------------------------------------------------------*/
  /* Post Move Trigger Checks: Check the new room for triggers.
   * Assumptions: The character has already truly left the was_in room. If
   * the entry trigger "prevents" movement into the room, it is the triggers
   * job to provide a message to the original was_in room. */
  if (!entry_mtrigger(ch) || !enter_wtrigger(&world[going_to], ch, dir)) {
    char_from_room(ch);
    char_to_room(ch, was_in);
    return 0;
  }

  /* Display arrival information to anyone in the destination room... */
  if (!AFF_FLAGGED(ch, AFF_SNEAK))
    act("$n has arrived.", TRUE, ch, 0, 0, TO_ROOM);

  /* ... and the room description to the character. */
  if (ch->desc != NULL)
    look_at_room(ch, 0);

  /* ... and Kill the player if the room is a death trap. */
  if (ROOM_FLAGGED(going_to, ROOM_DEATH) && GET_ADMLEVEL(ch) < ADMLVL_IMMORT)
  {
    mudlog(BRF, ADMLVL_IMMORT, TRUE, "%s hit death trap #%d (%s)", GET_NAME(ch), GET_ROOM_VNUM(going_to), world[going_to].name);
    death_cry(ch);
    extract_char(ch);
    return (0);
  }

  /* At this point, the character is safe and in the room. */
  /* Fire memory and greet triggers, check and see if the greet trigger
   * prevents movement, and if so, move the player back to the previous room. */
  entry_memory_mtrigger(ch);
  if (!greet_mtrigger(ch, dir))
  {
    char_from_room(ch);
    char_to_room(ch, was_in);
    look_at_room(ch, 0);
    /* Failed move, return a failure */
    return (0);
  }
  else
    greet_memory_mtrigger(ch);
  /*---------------------------------------------------------------------*/
  /* End: Post-move operations. */

  /* Only here is the move successful *and* complete. Return success for
   * calling functions to handle post move operations. */
  return (1);
}
Ejemplo n.º 7
0
void
zone_weather_change(struct zone_data *zone)
{
    int diff = 1, change;
    struct time_info_data local_time;

    if (ZONE_FLAGGED(zone, ZONE_NOWEATHER))
        return;

    set_local_time(zone, &local_time);

    if ((local_time.month >= 9) && (local_time.month <= 16))
        diff = (zone->weather->pressure > 1000 ? -1 :
            zone->weather->pressure < 970 ? 1 : 0);
    else
        diff = (zone->weather->pressure > 1025 ? -1 :
            zone->weather->pressure < 990 ? 1 : 0);

    zone->weather->change += diff * dice(4, 4) + (number(-15, 15));

    zone->weather->change = MAX(MIN(zone->weather->change, 15), -15);

    zone->weather->pressure += zone->weather->change;

    zone->weather->pressure = MAX(MIN(zone->weather->pressure, 1040), 960);

    change = CHANGE_NONE;

    switch (zone->weather->sky) {
    case SKY_CLOUDLESS:
        if (zone->weather->pressure < 990)
            change = 1;
        else if (zone->weather->pressure < 1010)
            if (dice(1, 4) == 1)
                change = 1;
        break;
    case SKY_CLOUDY:
        if (zone->weather->pressure < 970)
            change = 2;
        else if (zone->weather->pressure < 990)
            if (dice(1, 4) == 1)
                change = 2;
            else
                change = 0;
        else if (zone->weather->pressure > 1030)
            if (dice(1, 4) == 1)
                change = 3;

        break;
    case SKY_RAINING:
        if (zone->weather->pressure < 970)
            if (dice(1, 4) == 1)
                change = 4;
            else
                change = 0;
        else if (zone->weather->pressure > 1030)
            change = 5;
        else if (zone->weather->pressure > 1010)
            if (dice(1, 4) == 1)
                change = 5;

        break;
    case SKY_LIGHTNING:
        if (zone->weather->pressure > 1010)
            change = 6;
        else if (zone->weather->pressure > 990)
            if (dice(1, 4) == 1)
                change = 6;

        break;
    default:
        change = 0;
        zone->weather->sky = SKY_CLOUDLESS;
        break;
    }

    switch (change) {
    case 0:
        break;
    case 1:
        if (!number(0, 2))
            send_to_zone("The sky starts to get cloudy.\r\n", zone, 1);
        else if (zone->weather->sunlight == SUN_RISE)
            send_to_zone("A veil of clouds appears with the sunrise.\r\n",
                zone, 1);
        else if (zone->weather->sunlight == SUN_SET)
            send_to_zone
                ("As the suns dip below the horizon, clouds cover the sky.\r\n",
                zone, 1);
        else if (zone->weather->sunlight == SUN_DARK)
            send_to_zone("A layer of clouds obscures the stars.\r\n", zone, 1);
        else
            send_to_zone("Clouds begin to gather in the sky.\r\n", zone, 1);
        zone->weather->sky = SKY_CLOUDY;
        break;
    case 2:
        if (!number(0, 2))
            send_to_zone("It starts to rain.\r\n", zone, 1);
        else if (zone->weather->sunlight == SUN_RISE)
            send_to_zone
                ("Rain begins to fall across the land, as the double suns rise.\r\n",
                zone, 1);
        else if (zone->weather->sunlight == SUN_SET)
            send_to_zone
                ("As the suns sink below the horizon, rain begins to fall.\r\n",
                zone, 1);
        else if (zone->weather->sunlight == SUN_DARK)
            send_to_zone("Rain begins to fall from the night sky.\r\n", zone,
                1);
        else
            send_to_zone("Rain begins to fall from the sky.\r\n", zone, 1);
        zone->weather->sky = SKY_RAINING;
        break;
    case 3:
        if (!number(0, 2))
            send_to_zone("The clouds disappear.\r\n", zone, 1);
        else if (zone->weather->sunlight == SUN_RISE)
            send_to_zone("As the suns rise, the clouds in the sky vanish.\r\n",
                zone, 1);
        else if (zone->weather->sunlight == SUN_SET)
            send_to_zone
                ("The last of the clouds in the sky vanish with the sunset.\r\n",
                zone, 1);
        else if (zone->weather->sunlight == SUN_DARK)
            send_to_zone
                ("The clouds part, leaving a clear view of the stars.\r\n",
                zone, 1);
        else
            send_to_zone("The clouds have vanished, leaving a clear sky.\r\n",
                zone, 1);
        zone->weather->sky = SKY_CLOUDLESS;
        break;
    case 4:
        if (!number(0, 2))
            send_to_zone("Lightning starts to show in the sky.\r\n", zone, 1);
        else if (zone->weather->sunlight == SUN_RISE)
            send_to_zone
                ("Lightning and thunder begin to accompany the sunrise.\r\n",
                zone, 1);
        else if (zone->weather->sunlight == SUN_SET)
            send_to_zone
                ("As the suns set, lightning begins to flicker across the sky.\r\n",
                zone, 1);
        else if (zone->weather->sunlight == SUN_DARK)
            send_to_zone("The starry sky is lit by flashes of lightning.\r\n",
                zone, 1);
        else
            send_to_zone
                ("You can see lightning flickering across the sky.\r\n", zone,
                1);
        zone->weather->sky = SKY_LIGHTNING;
        break;
    case 5:
        if (!number(0, 2))
            send_to_zone("The rain stops.\r\n", zone, 1);
        else if (zone->weather->sunlight == SUN_RISE)
            send_to_zone
                ("The rain ceases as the twin suns rise above the horizon.\r\n",
                zone, 1);
        else if (zone->weather->sunlight == SUN_SET)
            send_to_zone
                ("The rain ceases as the twin suns sink below the horizon.\r\n",
                zone, 1);
        else if (zone->weather->sunlight == SUN_DARK)
            send_to_zone("The rain stops falling from the night sky.\r\n",
                zone, 1);
        else
            send_to_zone("The rain slacks up, then stops.\r\n", zone, 1);
        zone->weather->sky = SKY_CLOUDY;
        break;
    case 6:
        if (!number(0, 2))
            send_to_zone("The lightning stops.\r\n", zone, 1);
        else if (zone->weather->sunlight == SUN_RISE)
            send_to_zone
                ("The lightning ceases as the suns rise on a rainy day.\r\n",
                zone, 1);
        else if (zone->weather->sunlight == SUN_SET)
            send_to_zone("As the suns disappear, the lightning ceases.\r\n",
                zone, 1);
        else if (zone->weather->sunlight == SUN_DARK)
            send_to_zone("The lightning and thunder ceases.\r\n", zone, 1);
        else
            send_to_zone("The lightning seems to have stopped.\r\n", zone, 1);
        zone->weather->sky = SKY_RAINING;
        break;
    default:
        break;
    }
}