Re: send_to_charf, Take 2

From: Daniel A. Koepke (dkoepke@circlemud.org)
Date: 07/11/01


On Tue, 10 Jul 2001, George Greer wrote:

>   actf("TO_ROOM:0:$cYou tickle $n.\r\nTO_CHAR:0:$c$n tickles you.\r\n"
>         "TO_NOTCHAR:0:$c$c$n tickles $n.\r\n", ch, tch, tch, ch,
>         ch, tch, ch, tch);

Yuck.  Not to suggest that we actually redesign act(), but, if we were
going to, it'd be better to forget all the silly hacks and nonsuch.
Something simple and functional:

  void act(int type, struct char_data *ch, struct char_data *ex,
           const char *fmt, ...);

Where type is (TO_ROOM TO_CHAR TO_ZONE TO_ALL) with optional flags
(F_SLEEP F_INVIS F_OUTDOOR F_NOT_INVIS F_NOT_OUTDOOR F_INCLUDE).  I've
eliminated the idea of a general negation flag because of ambiguity when
the flags are combined.

The TO_xxx types are fairly clear in meaning.  TO_ROOM means that the
message will be sent to IN_ROOM(ch); TO_CHAR means that the message will
be sent to ch; TO_ZONE means that the message will be sent to the zone
containing IN_ROOM(ch) (however that's defined); TO_ALL is to everyone.
It would be possible to change the second argument into a general void
pointer and cast it with something like '*(room_rnum *)' to retrieve a
room real number for TO_ROOM while having TO_INROOM support the extant
behavior.  I don't believe there's any real need for this.  If you know
the room you're going to send to, you could just do

  act(TO_ROOM | F_INCLUDE, world[rnum].people, 0, ...

Something similar can be done for zones and with the addition of a small
function, it can be done when you only have a zone real number to work
with:

  struct char_data *get_zoned_player(zone_rnum zone)
  {
    struct descriptor_data *id;

    for (id = descriptor_list; id; id = id->next)
      if (STATE(id) == CON_PLAYING && id->character &&
          IN_ROOM(id->character) != NOWHERE &&
          world[IN_ROOM(id->character)].zone == zone)
        return (id->character);

    return (NULL);
  }

The framework thus allows for:

  act(TO_ZONE | F_INCLUDE, world[rnum].people, 0, ...
  act(TO_ZONE | F_INCLUDE, get_zoned_player(znum), 0, ...
  act(TO_ZONE | F_INCLUDE, ch, 0, ...

The first case happens when we have a room that we know is in our desired
zone, but only works if we _know_ that there's at least one person in this
room (otherwise, we're passing NULL as the second argument to the new
act(), which should probably then just return, without so much as a peep).
The second form is if we already have a zone real number -- our simple
get_zoned_player() function grabs the first player character in that zone.
The last and simplest is if we have a character we know is in our desired
zone.

The flags we can OR to the TO_xxx types are:

F_SLEEP: Mimics the old TO_SLEEP.
F_INVIS: Send exclusively to people that CANNOT see 'ch'.
F_NOT_INVIS: Mimics the old hide_invisible boolean.
F_OUTDOOR: Send exclusively to people that are outdoors.
F_NOT_OUTDOOR: Send exclusively to people that are not outdoors.
F_INCLUDE: Do not exclude a potential target _just_ because it is 'ch'.

The default behavior is to never send to sleeping targets, do not account
for visibility in deciding whether to send, do not account for whether or
not the target is outdoors when deciding whether to send, and always
exclude 'ch' from being a target (unless it is TO_CHAR, in which case,
such an exclusion is non-sensical).  If a character is passed as 'ex', it
is always excluded, regardless of F_INCLUDE.

This accomplishes all of the old behavior (plus a lot more) without much
fuss.  Consider the stock CircleMUD code

  act("You notice $N lunging at you!", FALSE, vict, 0, ch, TO_CHAR);
  act("$n notices you lunging at $m!", FALSE, vict, 0, ch, TO_VICT);
  act("$n notices $N lunging at $m!", FALSE, vict, 0, ch, TO_NOTVICT);

which would translate to

  act(TO_CHAR, vict, 0, "You notice $n lunging at you!", ch);
  act(TO_CHAR, ch, 0, "$n notices you lunging at $m!", vict, vict);
  act(TO_ROOM, ch, vict, "$n notices $n lunging at $m!", vict, ch, vict);

Of course, the original should probably have hide_invisible as TRUE in the
TO_NOTVICT version -- if so, the third one would have the F_NOT_INVIS flag
OR'd to it.

A final addition to make things very clean would be the addition of
positional parameter references.  So

  act(TO_ROOM, ch, vict, "$n notices $n lunging at $1#m!", vict, ch);

-dak

--
   +---------------------------------------------------------------+
   | FAQ: http://qsilver.queensu.ca/~fletchra/Circle/list-faq.html |
   | Archives: http://post.queensu.ca/listserv/wwwarch/circle.html |
   +---------------------------------------------------------------+



This archive was generated by hypermail 2b30 : 12/06/01 PST