Walking Up the Object Tree

Most of the day I have been puttering around with what seemed like a simple concept. All I want is to alter the listening to action to report the noise description of the loudest thing in the room (which could be the room, something in the room, or something in a closed container in the room). I have compiled a giant plate of spaghetti, which I have succeeded in throwing at the wall, and getting most of it to stick.

Sense-intensity is a kind of value.
The sense-intensities are naught, slight, distinct, potent, intense, and overwhelm.

Sense-obstruct is a kind of value.
The sense-obstructs are concede, block, reduce, and promote.

A thing has a sense-intensity called noiseLevel.
A room has a sense-intensity called noiseLevel.

A thing has some text called noiseDesc.
A room has some text called noiseDesc.

[A container can have no effect on sounds, block sound completely, reduce the sound, or amplify the sound.]
A container has a sense-obstruct called noiseBlock.

The Sound Lab is a room. "This room is full of machinery designed to detect, analyze and record sounds." The noiseLevel of the Sound Lab is slight. The noiseDesc of the Sound Lab is "All the machinery forms a concerto of electronic buzzes and tweets, and accompanying computer bloops and bleeps."

The Sound Booth is an open openable transparent enterable container in the Sound Lab. The description is "This is a huge, plexiglass booth. It is designed to completely block all sounds when closed. It is [if open]open[otherwise]closed[end if]." The noiseBlock of the Sound Booth is block.

[This is necessary if the player enters the booth and tries to listen.]
The can't reach outside closed containers rule does nothing when the holder of the player is the Sound Booth.

The Briefcase is a closed openable container in the Sound Lab. The description is "A plain, brown briefcase, with a brass plate that says 'Professor Lippencott' on it." The noiseBlock of the Briefcase is reduce.

The Time Bomb is a thing in the Briefcase. The description is "A pretty obvious bomb with a clock attached. The second hand of the clock ticks off the seconds as they fly by." The noiseLevel of the Time Bomb is distinct. The noiseDesc of the Time Bomb is "Tick. Tick. Tick."

Report an actor listening to (this is the revised report listening rule):
	if the actor is the player:
		let loud be the loudest;
		if loud is empty or (the number of entries in loud is 1 and entry 1 in loud is yourself):
			say "[We] [hear] only [ourselves]." (A);
		otherwise:
			repeat with obj running through loud:
				say "[noiseDesc of obj] ";
			say paragraph break;
	otherwise:
		say "[The actor] [listen]." (B).

The revised report listening rule is listed instead of the report listening rule in the report listening to rules.

To decide what list of objects is the loudest:
	let loud be a list of objects;
	let level be slight;
	let place be the holder of the player;
	repeat with obj running through things enclosed by place:
		say "[obj] ";
		if obj provides the property noiseLevel:
			let rnl be the relative noise level of obj;
			say "([noiseLevel of obj])([rnl])([if obj is visible]visible[otherwise]not visible[end if])";
			if rnl is greater than level:
				now level is rnl;
		say line break;
	let lrnl be the relative noise level of place;
	if lrnl is greater than level:
		now level is lrnl;
	if lrnl is level:
		say "[place] ([noiseLevel of place])([lrnl])[line break]";
		add the location to loud;
	repeat with obj running through things enclosed by place:
		if obj provides the property noiseLevel:
			let rnl be the relative noise level of obj;
			if rnl is level:
				add obj to loud;
	if loud is empty:
		repeat with obj running through invisible things enclosed by place:
			if obj provides the property noiseLevel:
				let rnl be the relative noise level of obj;
				if rnl is level:
					add obj to loud;
	if loud is empty:
		add yourself to loud;
	say "Level: [level][line break]Loud: [loud][line break]";
	decide on loud;

To decide what sense-intensity is the relative noise level of (obj - an object):
	let level be the noiseLevel of obj;
	let r be the holder of obj;
	if r is a person:
		now r is the holder of the holder of the obj;
	let p be the holder of the player;
	let t be the noiseLevel of p;
	if p is not the location and r is the location:
		if p provides the property noiseBlock:
			if p is closed:
				now level is level modified by noiseBlock of p;
	otherwise if r is not p:
		if r provides the property noiseBlock:
			if r is closed:
				now level is level modified by noiseBlock of r;
	decide on level.
		
To decide what sense-intensity is (si - a sense-intensity) modified by (sb - a sense-obstruct):
	let lvl be si;
	if sb is block:
		now lvl is naught;
	otherwise if sb is reduce:
		if lvl is not naught:
			now lvl is the sense-intensity before lvl;
	otherwise if sb is promote:
		if lvl is not overwhelm:
			now lvl is the sense-intensity after lvl;
	decide on lvl.

Test sounds with "listen / open briefcase / listen / put briefcase in booth / close booth / listen / open booth / close briefcase / close booth / listen".

The result from the test script clearly shows that the time bomb can still be heard, even when it is in a closed briefcase in a closed sound-proof booth.

The obvious reason is that the code only looks at the immediate holder of a thing, unless that’s a person. What I haven’t been able to figure out is how to recursively walk up a chain of containment, modifying the noiseLevel of a thing at each level. Something that will work for the scenario above, as well as a noisy cricket in a box, which is in a box, which is in a box, which is in a box, which is in a chest.

1 Like

I haven’t fully wrapped my head around your code, but I think the basic approach I’d take would be to do a loop running through the things enclosing the object in question, conditionally adding to some muffling factor as you go (like add .5 if the thing is an open container, 1.0 for a closed one, nothing for a supporter, etc.), and then just discount the resulting noise level by the final sum (like, multiply it by .5 to the muffling factor). There are probably lots of refinements one could make depending on the level of acoustic verisimilitude you’re aiming for, of course!

Is the idea that one hears only whatever the loudest chain of objects is, and the top of the chain is either the player or the holder of the player?

And will you need to determine what’s audible for NPCs or just the player?

1 Like

Not sure if I understand the spec, but maybe this’ll provide some ideas.

a thing has a number called the noiselevel.
a room has a number called the noiselevel.

Sense-obstruct is a kind of value.
The sense-obstructs are conceding, blocking, reducing, and promoting.
A container has a sense-obstruct. [ anonymous so can be used as adjectives ]

A thing has some text called noiseDesc.
A room has some text called noiseDesc.

The Sound Lab is a room. "This room is full of machinery designed to detect, analyze and record sounds." The noiseLevel of the Sound Lab is 1. The noiseDesc of the Sound Lab is "Al\
l the machinery forms a concerto of electronic buzzes and tweets, and accompanying computer bloops and bleeps."

The Sound Booth is an open openable transparent enterable blocking container in the Sound Lab. The description is "This is a huge, plexiglass booth. It is designed to completely bl\
ock all sounds when closed. It is [if open]open[otherwise]closed[end if]."

[This is necessary if the player enters the booth and tries to listen.]
The can't reach outside closed containers rule does nothing when the holder of the player is the Sound Booth.

The Briefcase is a closed openable reducing container in the Sound Lab. The description is "A plain, brown briefcase, with a brass plate that says 'Professor Lippencott' on it."

The Time Bomb is a thing in the Briefcase. The description is "A pretty obvious bomb with a clock attached. The second hand of the clock ticks off the seconds as they fly by." The \
noiseLevel of the Time Bomb is 2. The noiseDesc of the Time Bomb is "Tick. Tick. Tick."

audibility ceiling is an object that varies.
ambient is a number that varies.

to decide what object is the audibility-ceiling:
  let h be the holder of the player;
  while h is not a room and h is not a closed blocking container begin;
    now h is the holder of h;
  end while;
  decide on h.

The listening to action has a list of objects called the hearable.
setting action variables for listening to: truncate hearable to 0 entries.

carry out listening:
now the audibility ceiling is the audibility-ceiling;
say "audibility ceiling: [audibility ceiling].";
now ambient is the noisiness of the player;
say "ambient is [ambient].";
now hearable is discernible;


to decide what number is the noisiness of (obj - object):
  let level be the noiselevel of obj;
  if obj is the audibility ceiling, decide on level;
  let h be the holder of obj;
  while h is not the audibility ceiling and h is not the player begin;
    if h is a closed container begin;
      if h is blocking, decide on 0;
      if h is reducing, decrement level;
      else; if h is promoting, increment level;
    end if;
    increase level by the noiselevel of h;
    if level < 0, now level is 0;
    else; if level > 6, now level is 6;
    now h is the holder of h;
  end while;
  decide on level;

to decide what list of objects is discernible:
  let noisy be a list of objects;
  repeat with item running through things enclosed by the audibility ceiling begin;
    unless the first thing held by item is nothing, next; [ we're assuming there's no incorporation ]
     [ if we get past that unless, we know we're dealing with a leaf item ]
    if the noisiness of the item > ambient, add item to noisy;
    if the noisiness of the item > ambient, say "adding [item] to noisy.";
  end repeat;
  decide on noisy;

first after looking: try listening; continue the action.

after listening when hearable is empty: say "[We] [hear] only [ourselves]."

after listening to:
  say "hearable: [hearable].";
  repeat with item running through hearable begin;
    let h be the item;
    while h is not the player and h is not the audibility ceiling begin;
      say "[h]: [noiseDesc of h] ";
      now h is the holder of h;
    end while;
    say ".";
  end repeat;

Obviously it’s not trying to have pretty output…

There’s a built-in phrase common ancestor of ... with ... that’s helpful.

Following are some suggested changes:

suggested changes
[This is necessary if the player enters the booth and tries to listen.]
[The can't reach outside closed containers rule does nothing when the holder of the player is the Sound Booth.]

To decide which object is next level down from (T1 - object) to (T2 - object):
	if the common ancestor of T1 with T2 is nothing, decide on nothing;
	let level be T2;
	let current holder be holder of level;
	while current holder is not T1:
		now level is current holder;
		now current holder is holder of current holder;
	decide on level.

[compare to implicitly pass through barriers rule in Standard Rules]
To decide which sense-intensity is the noise level of (T1 - object) as heard by (T2 - object):
	let sound ceiling be the common ancestor of T1 with T2;
	if sound ceiling is nothing, decide on naught; [somewhere else entirely]
	let current stage be T1;
	let level be noiseLevel of T1;
	while current stage is not sound ceiling and current stage is not nothing: [T1 to ceiling]
		if current stage is a closed container:
			if current stage provides the property noiseBlock:
				now level is level modified by noiseBlock of current stage;
		now current stage is holder of current stage;
	while current stage is not T2: [ceiling to T2]
		let next stage be next level down from current stage to T2;
		if next stage is not T2 and next stage is a closed container:
			if next stage provides the property noiseBlock:
				now level is level modified by noiseBlock of next stage;
		now current stage is next stage;
	decide on level.	
	
To decide what sense-intensity is the relative noise level of (obj - an object):
	decide on the noise level of obj as heard by player.

To decide what list of objects is the loudest to (listener - object):
	let ceiling be listener;
	let selection be a list of objects; [empty]
	unless ceiling is a room, now ceiling is location of ceiling;
	if ceiling is nothing, decide on selection; [still empty]
	let max perceived be the noise level of ceiling as heard by listener;
	add ceiling to selection;
	repeat with item running through things enclosed by ceiling:
		let perceived be the noise level of item as heard by listener;
		if perceived is greater than max perceived:
			now max perceived is perceived;
			truncate selection to zero entries;
		if perceived is max perceived, add item to selection;
	decide on selection.

To decide what list of objects is the loudest:
	decide on the loudest to the player.

I think that may be doing what you want.

2 Likes

Pretty much. Everything has a noise level and LISTEN only reports the loudest thing(s). Containers can block, reduce or amplify the noise level of things in them, but only when closed. And, as a default, you can always hear yourself, regardless of the noise level assigned to yourself.

I hadn’t intended to worry about what’s audible for NPCs.

It most certainly does. Of course, it had to be an undocumented built-in phrase that helped.

Edit: One note, however. If the player enters the booth, you still get the can’t reach outside closed containers rule response.

Oh, right. I forgot there was a known bug affecting attempts to listen to a room.

It’s in routine TouchabilityCeiling() by way of the ambient sound rule. You’ll need to change the routine:

For 10.1:

Include (-

! ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
! Light.i6t: Touchability Ceiling
! ==== ==== ==== ==== ==== ==== ==== ==== ==== ====

[ TouchabilityCeiling original o p rv;
	o = original;
	while (o) {
		p = CoreOfParentOfCoreOf(o);
		if (p ofclass K1_room) return p;
		if (p == nothing) return o;
		! BEGIN MODIFICATION
		@push untouchable_silence;
		untouchable_silence = true;
		rv = FollowRulebook(REACHING_OUTSIDE_RB, p); 
		@pull untouchable_silence;
		if ((rv) && (RulebookFailed()))
			return p;
		! END MODIFICATION
		o = p;
	}
	return o;
];

-) replacing "TouchabilityCeiling".

For 6M62, the last line is instead:

-) replacing "Touchability Ceiling" in "Light.i6t".

If you would rather let the bug sit, you can probably just limit your “rule does nothing when…” part to the listening action.

Tried this:

The can't reach outside closed containers rule does nothing when the current action is listening.

Didn’t stop the rule.

There’s a difference between when the current action is... and just when.... (There’s a thread about the performance hit from using current action; it’s best to avoid using it when possible.)

I’m not getting the stray output with:

The can't reach outside closed containers rule does nothing when listening.
1 Like

I also had to change the following to make sure silenced ceilings weren’t added to the list:

To decide what list of objects is the loudest to (listener - object):
	let ceiling be listener;
	let selection be a list of objects; [empty]
	unless ceiling is a room:
		if the holder of ceiling is a closed container and noiseBlock of the holder of the ceiling is block:
			now ceiling is the holder of the ceiling;
		otherwise:
			now ceiling is the location of ceiling;
	if ceiling is nothing, decide on selection; [still empty]
	let max perceived be the noise level of ceiling as heard by listener;
	add ceiling to selection;
	repeat with item running through things enclosed by ceiling:
		let perceived be the noise level of item as heard by listener;
		if perceived is greater than max perceived:
			now max perceived is perceived;
			truncate selection to zero entries;
		if perceived is max perceived, add item to selection;
	if max perceived is naught:
		truncate selection to zero entries;
	decide on selection.

Edit: spoke too soon. More testing required.

Edit 2: So, I ran into two problems: 1) when the player enters the sound booth and closed it, they could still hear things outside the sound booth; and 2) if the max perceived was naught (i.e. in the sound booth alone), the player could hear things, but only if they were outside the booth and in a container.

The first problem had to do with setting the ceiling (unless ceiling is a room…). The ceiling was always the location of the listener. I had to modify that to account for the listener being in a closed, sound-proof container.

The second problem was simply that the selection needed to be emptied if the max perceived was naught.

The code above has been corrected.

The part with ceiling (poorly named) was to ensure that – assuming the listener is on-stage – then the noise of the containing room would have a chance to be included. Your model includes a default noiseLevel for rooms.

I left the loudest phrase returning a list full of objects with level naught so that you could see all objects in the room (and the room itself) were being considered. (They are all tied for “loudest,” even if that loudest is naught.) I only glanced at your revised report listening rule, so I didn’t suggest changes, but the place I would expect to make a change would be the line

	if loud is empty or (the number of entries in loud is 1 and entry 1 in loud is yourself):

which would become

	if loud is empty or (the relative noise level of entry 1 in loud is naught):

Since the soundproof booth reduces anything outside it to naught, you shouldn’t have to treat it specially.

The last place I looked! :wink: