# # Patch name: DynamicSound # Patch version: 1 # Author's name: Leonid Korogodsky # Author's email: leokor@math.ias.edu # Version of PennMUSH: 1.6.10-patch06 # Date patch made: August 4, 1997 # Author is willing to support (yes/no): NO # Patch format: diff -c # # # This is a contributed PennMUSH patch. Its use is subject to the # same restrictions found in PennMUSH's hdrs/copyrite.h file. # # No warranty is given for this patch. It is not necessarily going # to work on your system, with any version of PennMUSH other than # the one above, etc. # # If the author given above was willing to support the patch, you # should write to the author if you have any questions or problems. Do # *NOT* send email messages to Javelin or any PennMUSH mailing list about # this patch! # # Below this line is the author's description of the patch, # followed by the patch itself. If the patch is in context diff # format, you'll probably apply it by typing: patch < patchfile # in your top-level MUSH directory, unless instructed otherwise # below. # # WARNING for the PennMUSH developers!!! # # Adding this patch to the public release might inhibit # future changes to the global environment architecture, # as it introduces a bunch of new global variables. # # Put briefly: DO NOT DO IT, please! :) The patch below contains a powerful and flexible system of sound propagation. The major enhancement is the introduction of "sound codes" that are represented by some unprintable characters (existing only dynamically) which refer each to a particular piece of global data. A bit of history, coming together with an explanation of how the system works. It was based on my original (not involving a version of the dynamic() function) system of hardcoded sound propagation. In many fruitful talks with Lukthil@Elendor, the idea of a much more powerful system of dynamic sound was born. And now implemented by truely yours. :) The implementation is NOT perfect, though, since in an attempt to adhere to the existing PennMUSH's architecture, I didn't change the basics of the queue structure. So that the global environment is still being copied literally into the queue. A softcoded dynamic() function is defined, which is of the following syntax: dynamic(/, , ..., ) When it is evaluated within a string, it returns into it a single unprintable character, while all the dynamic data (the object with its attribute, and the arguments if any) are saved in the global environment. When another object is notify()'ed with a string containing any of such sound codes, the dynamic data are retrieved, and the referenced attribute is evaluated, with the arguments passed to it as %0, ..., %9. This simple idea allows for a particularly interesting feature of the system, namely, that it is softcode-customizable. The attribute referenced by the dynamic() function can be whatever you want, and can be changed at any time. In particular, such functions as speak(), write(), and whisper() for language system, whisper() or mutter() without languages, etc. can be easily @function'ed as instances of dynamic(). It goes without saying that they can be used anywhere, in virtually any message whatsoever that can generated by a user in the game. Be it speech, attributes, channels, mail, @walls, etc. And with as many extra arguments as you wish. Also, the sound codes can be passed into queue, so that an object that has "heard" the sound, can not only understand (or not understand, or partially understand) the meaning, but it can also repeat the actual "sound of it" to another object that might understand it fully. A bit of explanation on how the system is implemented. I keep track of the top of the dynamic stack. When a dynamic() function is evaluated, the integer referring to the position of the topmost unit of dynamic data in the array, after adding a base number to insure unpritability, is typecast into a character returned by the function. When this sound code is resolved, the character is typecast back into integer, and a simple hash function immediately points at the unit of dynamic data referred to by our dynamic() function. *** dune.h.dist.orig Tue Jul 15 10:01:23 1997 --- dune.h.dist Wed Jul 23 12:52:56 1997 *************** *** 426,426 **** --- 426,447 ---- + /* If defined, a special system enables dynamic sound propagation. + * Allowing for any string to be read differently by the viewer. + * A flexible system that can be used in coding languages + * and many other things. + */ + /* #define DYNAMIC_SOUND */ + /* If defined, unprintable characters are not allowed in the attributes + * and the @mail messages. Highly recommended for the purposes of + * database editing. Necessary if you define DYNAMIC_SOUND. + */ + /* #define CLEAN_DATABASE /* */ + + #ifdef DYNAMIC_SOUND + + #define CLEAN_DATABASE + + /* If defined, the dynamic() function is restricted to wizards and royals. */ + /* #define RESTRICT_DYNAMIC /* */ + + #endif /* DYNAMIC_SOUND */ + #endif /* __DUNE_H */ *** hdrs/conf.h.orig Mon Jul 21 11:32:52 1997 --- hdrs/conf.h Sun Aug 3 11:15:45 1997 *************** *** 35,40 **** --- 35,46 ---- /* delimiter for lists of exit aliases */ #define EXIT_DELIMITER ';' + #ifdef DYNAMIC_SOUND + #define DYN_START 161 /* Change these settings only at your own risk! */ + #define DYN_FINISH 255 /* The characters between (char) 161 and (char) 255 */ + #define DYN_MAX DYN_FINISH - DYN_START + 1 /* should be safe to use. */ + #endif + #define OBJECT_ENDOWMENT(cost) (((cost)-5)/5) /* added for recycling, return value of object */ *** hdrs/externs.h.orig Mon Jul 21 10:57:22 1997 --- hdrs/externs.h Thu Jul 31 20:24:38 1997 *************** *** 102,108 **** --- 102,128 ---- extern void parse_que _((dbref player, const char *command, dbref cause)); extern int nfy_que _((dbref sem, int key, int count)); + #ifdef DYNAMIC_SOUND + struct dsound { + unsigned char *dvalue; + char *dargs[10]; + dbref execobj; + dbref callobj; + dbref enactobj; + int pass; + }; + + typedef struct dsound DSOUND; + + extern DSOUND *dyn_data[DYN_MAX]; + extern int dyn_top; + extern char *dyn_string; + extern dbref audience; + extern int dyn_pass; + + #endif /* DYNAMIC_SOUND */ + /* From create.c */ extern dbref do_dig _((dbref player, const char *name, char **argv, int tport)); extern dbref do_create _((dbref player, char *name, int cost)); *************** *** 125,130 **** --- 145,156 ---- extern const char *power_description _((dbref thing)); extern object_flag_type find_power _((const char *name)); + #ifdef DYNAMIC_SOUND + /* From funstr.c */ + extern char *resolve_dynamic _((dbref player, const char *msg)); + extern char *strip_unprint _((const char *raw)); + #endif + /* From game.c */ #define notify(p,m) notify_check(p,m,0) #define notify_noecho(p,m) notify_check(p,m,1) *** hdrs/function.h.orig Mon Jul 21 11:35:04 1997 --- hdrs/function.h Mon Jul 21 11:36:09 1997 *************** *** 282,287 **** --- 282,291 ---- FUNCTION_PROTO(fun_edit); /* funstr.c */ FUNCTION_PROTO(fun_left); /* funstr.c */ FUNCTION_PROTO(fun_right); /* funstr.c */ + #ifdef DYNAMIC_SOUND + FUNCTION_PROTO(fun_dynamic); /* funstr.c */ + FUNCTION_PROTO(fun_stripdyn); /* funstr.c */ + #endif FUNCTION_PROTO(fun_time); /* funtime.c */ FUNCTION_PROTO(fun_secs); /* funtime.c */ FUNCTION_PROTO(fun_convsecs); /* funtime.c */ *** src/bsd.c.orig Mon Jul 21 11:42:21 1997 --- src/bsd.c Thu Jul 31 16:57:00 1997 *************** *** 1610,1616 **** struct descriptor_data *d; char *command; { ! int j; depth = 0; (d->cmds)++; --- 1610,1616 ---- struct descriptor_data *d; char *command; { ! int j, k; depth = 0; (d->cmds)++; *************** *** 1673,1678 **** --- 1673,1684 ---- wenv[j] = (char *) NULL; renv[j][0] = '\0'; } + #ifdef DYNAMIC_SOUND + dyn_top = 0; + dyn_string = NULL; + audience = NOTHING; + dyn_pass = 0; + #endif process_command(d->player, command, d->player, 1); if (d->output_suffix) { *** src/cque.c.orig Mon Jul 21 12:49:16 1997 --- src/cque.c Sun Aug 3 17:10:43 1997 *************** *** 47,52 **** --- 47,57 ---- int left; /* seconds left until execution */ char *env[10]; /* environment, from wild match */ char *rval[10]; /* environment, from setq() */ + #ifdef DYNAMIC_SOUND + DSOUND *denv[DYN_MAX]; /* dynamic-sound stack */ + int dtop; /* top of the dynamic-sound stack */ + char *dstr; /* dynamic-sound string */ + #endif char *comm; /* command to be executed */ }; *************** *** 78,83 **** --- 83,91 ---- void do_allrestart _((dbref player)); static void do_raw_restart _((dbref victim)); void do_restart_com _((dbref player, const char *arg1)); + #ifdef DYNAMIC_SOUND + DSOUND *dynamic_copy _((DSOUND *ds)); + #endif void parse_que(player, command, cause) *************** *** 176,181 **** --- 184,197 ---- } if (point->comm) mush_free((Malloc_t) point->comm, "bqueue_comm"); + #ifdef DYNAMIC_SOUND + for (a = 0; a < DYN_MAX; a++) { + if (point->denv[a]) + mush_free((Malloc_t) point->denv[a], "bqueue_denv"); + } + if (point->dstr) + mush_free((Malloc_t) point->dstr, "bqueue_dstr"); + #endif mush_free((Malloc_t) point, "BQUE"); } *************** *** 244,249 **** --- 260,283 ---- add_check("bqueue_rval"); #endif } + #ifdef DYNAMIC_SOUND + tmp->dtop = dyn_top; + for (a = 0; a < dyn_top; a++) { + tmp->denv[a] = dynamic_copy(dyn_data[a]); + #ifdef MEM_CHECK + add_check("bqueue_denv"); + #endif + } + for (; a < DYN_MAX; a++) + tmp->denv[a] = NULL; + if (dyn_string) { + tmp->dstr = (char *) strdup(dyn_string); + #ifdef MEM_CHECK + add_check("bqueue_dstr"); + #endif + } else + tmp->dstr = NULL; + #endif /* DYNAMIC_SOUND */ if (Typeof(cause) == TYPE_PLAYER) { if (qlast) { qlast->next = tmp; *************** *** 304,309 **** --- 338,361 ---- #endif } } + #ifdef DYNAMIC_SOUND + tmp->dtop = dyn_top; + for (a = 0; a < dyn_top; a++) { + tmp->denv[a] = dynamic_copy(dyn_data[a]); + #ifdef MEM_CHECK + add_check("bqueue_denv"); + #endif + } + for (; a < DYN_MAX; a++) + tmp->denv[a] = NULL; + if (dyn_string) { + tmp->dstr = (char *) strdup(dyn_string); + #ifdef MEM_CHECK + add_check("bqueue_dstr"); + #endif + } else + tmp->dstr = NULL; + #endif if (wait >= 0) tmp->left = mudtime + wait; *************** *** 453,458 **** --- 505,521 ---- else renv[a][0] = '\0'; } + #ifdef DYNAMIC_SOUND + dyn_top = qfirst->dtop; + for (a = 0; a < dyn_top; a++) { + dyn_data[a] = dynamic_copy(qfirst->denv[a]); + dyn_data[a]->pass++; + } + if (qfirst->dstr) + dyn_string = qfirst->dstr; + else + dyn_string = NULL; + #endif s = qfirst->comm; while (*s) { r = ccom; *************** *** 1076,1078 **** --- 1139,1164 ---- do_raw_restart(victim); } } + + #ifdef DYNAMIC_SOUND + DSOUND * + dynamic_copy(ds) + DSOUND *ds; + { + DSOUND *ts; + int k; + + ts = (DSOUND *) mush_malloc((unsigned) sizeof(DSOUND), "DSOUND"); + ts->dvalue = ds->dvalue; + for (k = 0; (k < 10) && (ds->dargs[k]); k++) + ts->dargs[k] = ds->dargs[k]; + for (; k < 10; k++) + ts->dargs[k] = NULL; + ts->execobj = ds->execobj; + ts->callobj = ds->callobj; + ts->enactobj = ds->enactobj; + ts->pass = ds->pass; + + return ts; + } + #endif /* DYNAMIC_SOUND */ *** src/extmail.c.orig Mon Jul 21 23:11:17 1997 --- src/extmail.c Mon Jul 21 23:45:27 1997 *************** *** 928,937 **** newp->from = player; #ifdef MAIL_SUBJECTS /* Deal with the subject */ if (subject) strcpy(sbuf, uncompress(subject)); else ! strcpy(sbuf, "(no subject)"); if ((flags & M_FORWARD) && !string_prefix(sbuf, "Fwd:")) newp->subject = u_strdup(compress(chopstr(tprintf("Fwd: %s", sbuf), SUBJECT_LEN))); else if ((flags & M_REPLY) && !string_prefix(sbuf, "Re:")) --- 928,942 ---- newp->from = player; #ifdef MAIL_SUBJECTS /* Deal with the subject */ + #ifdef CLEAN_DATABASE if (subject) + strcpy(sbuf, strip_unprint(uncompress(subject))); + #else + if (subject) strcpy(sbuf, uncompress(subject)); + #endif else ! strcpy(sbuf, "(No Subject)"); if ((flags & M_FORWARD) && !string_prefix(sbuf, "Fwd:")) newp->subject = u_strdup(compress(chopstr(tprintf("Fwd: %s", sbuf), SUBJECT_LEN))); else if ((flags & M_REPLY) && !string_prefix(sbuf, "Re:")) *************** *** 946,952 **** --- 951,961 ---- /* Forwarding passes the message already compressed */ newp->message = u_strdup((unsigned char *) message); } else + #ifdef CLEAN_DATABASE + newp->message = u_strdup(compress(strip_unprint(message))); + #else newp->message = u_strdup(compress(message)); + #endif newp->time = u_strdup(compress(tbuf1)); newp->read = flags & M_FMASK; /* Send to folder 0 */ *** src/function.c.orig Mon Jul 21 11:36:34 1997 --- src/function.c Wed Jul 23 12:54:40 1997 *************** *** 148,153 **** --- 148,156 ---- {"DIST3D", fun_dist3d, 6, 6, FN_REG}, {"DIV", fun_div, 2, 2, FN_REG}, {"DOING", fun_doing, 1, 1, FN_REG}, + #ifdef DYNAMIC_SOUND + {"DYNAMIC", fun_dynamic, 1, 11, FN_REG}, + #endif {"EDEFAULT", fun_edefault, 2, 2, FN_NOPARSE}, {"EDIT", fun_edit, 3, 3, FN_REG}, {"ELEMENT", fun_element, 3, 3, FN_REG}, *************** *** 328,333 **** --- 331,339 ---- {"STATS", fun_lstats, 0, 1, FN_REG}, {"STRCAT", fun_strcat, 1, INT_MAX, FN_REG}, {"STRIPANSI", fun_stripansi, 1, -1, FN_REG}, + #ifdef DYNAMIC_SOUND + {"STRIPDYN", fun_stripdyn, 1, -1, FN_REG}, + #endif {"STRLEN", fun_strlen, 1, -1, FN_REG}, {"STRMATCH", fun_strmatch, 2, 2, FN_REG}, {"SUB", fun_sub, 2, 2, FN_REG}, *** src/funstr.c.orig Mon Jul 21 10:54:24 1997 --- src/funstr.c Thu Jul 31 23:05:18 1997 *************** *** 21,26 **** --- 21,33 ---- #endif int get_gender _((dbref player)); + #ifdef DYNAMIC_SOUND + char *strip_dynamic _((const char *raw)); + char *resolve_dynamic _((dbref player, const char *msg)); + #endif + #ifdef CLEAN_DATABASE + char *strip_unprint _((const char *raw)); + #endif int get_gender(player) *************** *** 873,875 **** --- 880,1032 ---- safe_str(r, buff, bp); } } + + #ifdef DYNAMIC_SOUND + /* ARGSUSED */ + FUNCTION(fun_dynamic) + { + dbref obj; + ATTR *attrib; + int code, k; + + #ifdef RESTRICT_DYNAMIC + if (!Hasprivs(executor)) { + notify(executor, "Permission denied."); + return; + } + #endif + + /* find the user function attribute */ + parse_attrib(executor, args[0], &obj, &attrib); + + if (!attrib || !Can_Read_Attr(executor, obj, attrib)) { + safe_str("#-1 NO ATTRIBUTE FOUND", buff, bp); + return; + } + #ifdef SAFER_UFUN + if ((!Wizard(executor) && Wizard(obj)) || + (!Hasprivs(executor) && Hasprivs(obj))) + return; + #endif + + /* Check if the dynamic-sound stack does not overflow */ + if (dyn_top >= DYN_MAX) { + safe_str("#-1 DYNAMIC STACK OVERFLOW", buff, bp); + return; + } + + /* Push the global dynamic-sound stack */ + + dyn_data[dyn_top]->dvalue = u_strdup(attrib->value); + if (nargs > 11) + nargs = 11; + for (k = 0; k < nargs - 1; k++) + (dyn_data[dyn_top]->dargs)[k] = strdup(args[k + 1]); + for (; k < 10; k++) + (dyn_data[dyn_top]->dargs)[k] = NULL; + dyn_data[dyn_top]->execobj = obj; + dyn_data[dyn_top]->callobj = executor; + dyn_data[dyn_top]->enactobj = enactor; + dyn_data[dyn_top]->pass = 1; + + /* Encode it into the output with a special character */ + code = DYN_START + dyn_top; + dyn_top++; + safe_chr((char) code, buff, bp); + } + + char * + resolve_dynamic(player, msg) + dbref player; + const char *msg; + { + char tbuf1[BUFFER_LEN]; + char tbuf2[BUFFER_LEN]; + char *bp1, *bp2, *cp, *tp; + const char *str; + dbref executor, caller, enactor; + int code, k; + + audience = player; + bp1 = tbuf1; + cp = msg; + while (*cp) { + code = ((int) *cp) + DYN_MAX; + if ((code >= 0) && (code < dyn_top)) { + if (dyn_data[code]) { + /* Retrieve the dynamic-sound data */ + str = tp = safe_uncompress(dyn_data[code]->dvalue); + for (k = 0; (dyn_data[code]->dargs)[k]; k++) + wenv[k] = strdup((dyn_data[code]->dargs)[k]); + for (; k < 10; k++) + wenv[k] = NULL; + executor = dyn_data[code]->execobj; + caller = dyn_data[code]->callobj; + enactor = dyn_data[code]->enactobj; + dyn_pass = dyn_data[code]->pass; + /* Evaluate dynamic sound */ + strcpy(tbuf2, ""); + bp2 = tbuf2; + process_expression(tbuf2, &bp2, &str, executor, caller, enactor, + PE_DEFAULT, PT_DEFAULT, NULL); + *bp2 = '\0'; + safe_str(tbuf2, tbuf1, &bp1); + free(tp); + } + } else + safe_chr(*cp, tbuf1, &bp1); + cp++; + } + *bp1 = '\0'; + + /* Reset the global dynamic-sound data */ + audience = NOTHING; + dyn_pass = 0; + + return (strip_dynamic(tbuf1)); + } + + char * + strip_dynamic(raw) + const char *raw; + { + char *cp = raw; + char tbuf1[BUFFER_LEN]; + char *bp1; + + bp1 = tbuf1; + while (*cp) { + if (((int) *cp) >= 0) + safe_chr(*cp, tbuf1, &bp1); + cp++; + } + *bp1 = '\0'; + return tbuf1; + } + + /* ARGSUSED */ + FUNCTION(fun_stripdyn) + { + safe_str(strip_dynamic(args[0]), buff, bp); + } + #endif /* DYNAMIC_SOUND */ + + #ifdef CLEAN_DATABASE + char * + strip_unprint(raw) + const char *raw; + { + char *cp = raw; + char tbuf1[BUFFER_LEN]; + char *bp1; + + bp1 = tbuf1; + while (*cp) { + if (isprint(*cp)) + safe_chr(*cp, tbuf1, &bp1); + cp++; + } + *bp1 = '\0'; + return tbuf1; + } + #endif /* CLEAN_DATABASE */ *** src/game.c.orig Thu Jul 17 13:08:32 1997 --- src/game.c Sun Aug 3 17:04:48 1997 *************** *** 91,96 **** --- 91,104 ---- extern dbref cplr; extern char ccom[]; + #ifdef DYNAMIC_SOUND + DSOUND *dyn_data[DYN_MAX]; + int dyn_top; + char *dyn_string; + dbref audience; + int dyn_pass; + #endif + static int paranoid_dump = 0; /* if paranoid, scan before dumping */ int paranoid_checkpt = 0; /* write out an okay message every x objs */ static void dump_database_internal _((void)); *************** *** 242,247 **** --- 250,258 ---- char clean[BUFFER_LEN]; char *bp; char *preserve[10]; + #ifdef DYNAMIC_SOUND + char *resolved; + #endif if (!GoodObject(player)) return; *************** *** 249,259 **** --- 260,280 ---- depth--; return; } + #ifdef DYNAMIC_SOUND + dyn_string = msg; + resolved = resolve_dynamic(player, msg); #ifdef EXTENDED_ANSI + strcpy(clean, strip_ansi(resolved)); + #else + strcpy(clean, resolved); + #endif + #else /* DYNAMIC_SOUND */ + #ifdef EXTENDED_ANSI strcpy(clean, strip_ansi(msg)); #else strcpy(clean, msg); #endif + #endif /* DYNAMIC_SOUND */ switch (Typeof(player)) { case TYPE_ROOM: *************** *** 276,282 **** --- 297,307 ---- return; break; /* NOTREACHED */ case TYPE_PLAYER: + #ifdef DYNAMIC_SOUND + raw_notify(player, resolved); + #else raw_notify(player, msg); + #endif #ifndef PLAYER_LISTEN depth--; return; *************** *** 289,295 **** --- 314,324 ---- safe_str(Name(player), tbuf1, &bp); safe_chr('>', tbuf1, &bp); safe_chr(' ', tbuf1, &bp); + #ifdef DYNAMIC_SOUND + safe_str(resolved, tbuf1, &bp); + #else safe_str(msg, tbuf1, &bp); + #endif *bp = '\0'; raw_notify(db[player].owner, tbuf1); } *************** *** 306,316 **** --- 335,351 ---- #ifdef PLAYER_NOAHEAR if (Typeof(player) != TYPE_PLAYER) { #endif + #ifdef DYNAMIC_SOUND + dyn_string = msg; + #endif if (speaker != player) charge_action(speaker, player, "AHEAR"); else charge_action(speaker, player, "AMHEAR"); charge_action(speaker, player, "AAHEAR"); + #ifdef DYNAMIC_SOUND + dyn_string = NULL; + #endif #ifdef PLAYER_NOAHEAR } #endif *************** *** 346,352 **** PE_DEFAULT, PT_DEFAULT, NULL); if (bp != tbuf1) safe_chr(' ', tbuf1, &bp); ! safe_str(clean, tbuf1, &bp); *bp = '\0'; free((Malloc_t) asave); restore_global_regs("inprefix_save", preserve); --- 381,387 ---- PE_DEFAULT, PT_DEFAULT, NULL); if (bp != tbuf1) safe_chr(' ', tbuf1, &bp); ! safe_str(msg, tbuf1, &bp); *bp = '\0'; free((Malloc_t) asave); restore_global_regs("inprefix_save", preserve); *************** *** 353,363 **** for (j = 0; j < 10; j++) wenv[j] = wsave[j]; } if (IS(player, TYPE_THING, THING_PUPPET)) notify_except2(db[player].contents, player, Owner(player), ! (d) ? tbuf1 : clean); else ! notify_except(db[player].contents, player, (d) ? tbuf1 : clean); } } } --- 388,402 ---- for (j = 0; j < 10; j++) wenv[j] = wsave[j]; } + /* This is gonna modify dyn_string */ if (IS(player, TYPE_THING, THING_PUPPET)) notify_except2(db[player].contents, player, Owner(player), ! (d) ? tbuf1 : msg); else ! notify_except(db[player].contents, player, (d) ? tbuf1 : msg); ! #ifdef DYNAMIC_SOUND ! dyn_string = msg; /* restore the value */ ! #endif } } } *************** *** 721,728 **** const char *conf; { FILE *f; ! int a; ! const char *infile, *outfile; #ifdef USE_MAILER const char *mailfile; --- 760,766 ---- const char *conf; { FILE *f; ! int a, b; const char *infile, *outfile; #ifdef USE_MAILER const char *mailfile; *************** *** 736,741 **** --- 774,790 ---- wnxt[a] = NULL; rnxt[a] = NULL; } + #ifdef DYNAMIC_SOUND + for (a = 0; a < DYN_MAX; a++) { + dyn_data[a] = (DSOUND *) mush_malloc((unsigned) sizeof(DSOUND), "DSOUND"); + if (!dyn_data[a]) + panic("Out of memory."); + } + dyn_top = 0; + dyn_string = NULL; + audience = NOTHING; + dyn_pass = 0; + #endif /* set MUSH start time */ start_time = time((time_t *) 0); *************** *** 3797,3802 **** --- 3846,3855 ---- notify(player, "The chat system is disabled."); #endif + #ifdef DYNAMIC_SOUND + notify(player, "The dynamic sound system is enabled."); + #endif + #ifdef QUEUE_PER_OWNER notify(player, "Queue limits are maintained per-owner."); #else *** src/parse.c.orig Mon Jul 21 12:43:31 1997 --- src/parse.c Wed Jul 30 23:05:26 1997 *************** *** 380,385 **** --- 380,393 ---- case '#': /* enactor dbref */ safe_str(unparse_dbref(enactor), buff, bp); break; + #ifdef DYNAMIC_SOUND + case '^': /* listener dbref */ + safe_str(unparse_dbref(audience), buff, bp); + break; + case '_': /* number of dynamic-sound queue passes */ + safe_str(unparse_integer(dyn_pass), buff, bp); + break; + #endif case '?': /* function limits */ if (pe_info) { safe_str(unparse_integer(pe_info->fun_invocations), buff, bp); *************** *** 416,421 **** --- 424,436 ---- case 'c': /* command line */ safe_str(ccom, buff, bp); break; + #ifdef DYNAMIC_SOUND + case 'D': + case 'd': /* last resolved dynamic-sound string */ + if (dyn_string) + safe_str(dyn_string, buff, bp); + break; + #endif case 'L': case 'l': /* enactor location dbref */ /* The security implications of this have *** game/txt/hlp/penn.hlp.orig Mon Jul 21 15:26:41 1997 --- game/txt/hlp/penn.hlp Thu Jul 31 21:39:28 1997 *************** *** 2020,2025 **** --- 2020,2050 ---- location. Any object dropped in the room (if it isn't STICKY) will go to that location. If the room is STICKY, the drop-to will be delayed until the last person in the room has left. + & DYNAMIC SOUND + + If the dynamic sound system is enabled, the dynamic() function becomes + available. It can be used in a very flexible way to make it possible + for the same sound to be heard differently by different objects. In + the following example, %^ refers to the dbref of the listening object. + + Example: + > &SOUND Object = [name(%^)] + Object - Set. + > say Hello, [dynamic(Object/SOUND)]! + You hear: Hello, Wizard! + Tom hears: Hello, Tom! + + For more, see DYNAMIC2. + & DYNAMIC2 + + The dynamic sound can be passed into the queue. For example, with + the $-patterns, ^-patterns, @listen/@ahear, @force, @trigger, @wait. + It is automatically propagated as any sound. This makes it particularly + useful for coding a language system. In particular, making it possible + for an object to "remember" the sound, even if it didn't understand + the meaning, and to repeat it to someone who can understand. + + See also: dynamic(), stripdyn(). & EXITS EXITS An exit links one room to another room. If an exit is set DARK it will *************** *** 2154,2160 **** %qN = the equivalent of r(N), a register set by a setq() function. %? (accounting) = Current values of function invocation count and recursion depth count. ! & SUCCESS SUCCESS You successfully use an object when you take it. You use an exit successfully when you go through it. You successfully use --- 2179,2206 ---- %qN = the equivalent of r(N), a register set by a setq() function. %? (accounting) = Current values of function invocation count and recursion depth count. ! ! For the substitutions coming with the dynamic sound system, ! see SUBSTITUTIONS3. ! & SUBSTITUTIONS3 ! ! If the dynamic sound system is enabled, the following substitutions ! become available: ! ! When used in an attribute referenced by a dynamic() function: ! ! %^ = dbref of the listening object ! %_ = number of times the message was passed into the queue ! ! (When not in such an attribute, %^ returns #-1, and %_ returns 0.) ! ! When used in a ^-listening pattern or @ahear/@amhear/@aahear: ! ! %d = the full message with unresolved sound codes ! ! (When not in a listening pattern, %d returns the empty string.) ! ! See also: DYNAMIC SOUND, dynamic(). & SUCCESS SUCCESS You successfully use an object when you take it. You use an exit successfully when you go through it. You successfully use *** game/txt/hlp/pennfunc.hlp.orig Mon Jul 21 15:18:29 1997 --- game/txt/hlp/pennfunc.hlp Thu Jul 31 21:40:08 1997 *************** *** 145,155 **** alphamin() alphamax() art() capstr() cat() center() comp() dec() decrypt() delete() ! edit() encrypt() escape() inc() lcstr() ! left() lit() ljust() merge() mid() ! pos() repeat() reverse() right() rjust() ! scramble() secure() space() squish() strcat() ! stripansi() strlen() switch() trim() ucstr() & Utility functions These functions don't quite fit into any other category. --- 145,156 ---- alphamin() alphamax() art() capstr() cat() center() comp() dec() decrypt() delete() ! dynamic() edit() encrypt() escape() inc() ! lcstr() left() lit() ljust() merge() ! mid() pos() repeat() reverse() right() ! rjust() scramble() secure() space() squish() ! strcat() stripansi() stripdyn() strlen() switch() ! trim() ucstr() & Utility functions These functions don't quite fit into any other category. *************** *** 1194,1199 **** --- 1195,1231 ---- stripansi() Returns the string with all ansi codes removed. + & STRIPDYN() + stripdyn() + + Returns the string with all dynamic codes removed. + + See also: dynamic(). + & DYNAMIC() + dynamic([/], [, , , ..., ]) + + This function encodes text information, replacing it with a special + unprintable character called "sound code". When at a later time, some + object is notified with a string containing that character, it is + replaced with the evaluated contents of the referenced attribute, + with the arguments , , ..., passed as %0, %1, ..., + %9 respectively. The dynamic sound can be passed from one queue cycle + into another. But no more than 95 sound codes can be used in each + single queue cycle. + + The attribute referenced by the dynamic() function understands all the + usual %-substitutions and two extra ones: %^ returns the dbref of the + object that is being notified, and %_ returns the number of times the + dynamic sound was passed into the queue. When not in such attribute, + %^ returns #-1, and %_ returns 0. + + A special %-substitution %d, when used in ^-listening patterns and + @ahear/@amhear/@aahear, returns the full message heard by the object + with unresolved sound codes. Note that the listening pattern matching + is still performed with the resolved sound codes. When not in a listening + pattern, %d returns the empty string. + + See also: DYNAMIC SOUND, stripdyn(). & ABS() abs()