Relations?

I have a scenario where I’m trying to setup a system to determine the relationship between some characters.

It works like this:

There are three people (not including the player) in a room who are talking (i’m just using Say to say the quips from a Table). Two of them are listening to one (the Host). I want the two listening characters to gain “relationship points” with one another whenever their quips agree. For the purpose of this game, “agreement” is denoted by quips that are in the same font style (bold quips or italic quips).

I’m kind of at a loss as to how to do this.

-Is there a way to get the text from a table (maybe the [italic type] or [bold type] substitutions) so that i can tell, when the text is printed, if the two listeners have agreed with each other?

-I’ve tried something like this:

A person has some text called quipType.  
	
if the quipType of a random person who is not the player is "italicsUsed":
     [do stuff];

…and that would work, but I can’t figure out the syntax to include the other non-player person. If i try to add any named person to that code, it won’t compile (for example, if i were to say: if the quipType of a random person who is not the player or John is “italicsUsed”, it yells at me).

-I’ve tried to think of how i could do this with relations, but I don’t really understand those that well. Is there something I’m missing?

If you’ve got the quips in a table, it seems like the best solution would be to add another column that says whether each quip is of the right type (bold or italic or whatever). Checking that entry would be easier than trying to extract something from the text itself.

I’m also not quite sure what you’re doing with “a random person.” That seems like, even if you get it to work, it’ll pick a random person instead of checking both people. Maybe you want to loop over people in the location and check whether their quip type matches the quip type you get from the table?

Hi, thanks for responding.

Can you give an example of how you would loop through people in a location? That’s pretty much what i want to do, though there is an additional problem (which i didn’t mention): the people who are in the location changes.

So at any time, i need to be able to find two people who are not the Host, and also not the player, who are in agreement (there are never any more than 4 people in the location, including the player, but one is the Host of the conversation, and needs to be left out of the search).

The random person thing was a bad attempt to narrow down the people in the location.

Repeat with the subject running through people in the location:

What’s the idea behind the bold/italic thing?

So one thing I didn’t quite realize was that you needed the listeners’ quips to agree with each other. That makes it a little more complicated; one thing you can do is have one loop inside another.

[code]Lecture Hall is a room. The professor is a woman in Lecture Hall.

Statler and Waldorf are men in Lecture Hall.

Pintel, Ragetti, Tahei, and Matsahichi are men.

Definition: A person is a listener if it is not the player and it is not the professor.

Origin is a kind of value. The origins are null, The Muppet Show, The Hidden Fortress, and Pirates of the Caribbean.
A person has an origin.
The origin of Statler is the Muppet Show. The origin of Waldorf is the Muppet Show. The origin of Tahei is The Hidden Fortress. The origin of Matsahichi is The Hidden Fortress. The origin of Pintel is Pirates of the Caribbean. The origin of Ragetti is Pirates of the Caribbean.

Every turn:
repeat with first subject running through listener people in the location:
repeat with second subject running through listener people in the location:
if second subject is not first subject and the origin of second subject is the origin of first subject and the origin of first subject is not null:
say “[First subject] and [second subject] come from the same work!”

Every turn:
let departee be a random listener in Lecture Hall;
let enteree be a random off-stage listener;
say “[Departee] excuses [themselves] and [Enteree] enters.”;
now departee is nowhere;
now enteree is in Lecture Hall.[/code]

Another thing I did there was define “listener” as someone who is not the professor and not the player, which is a way of getting the syntax to include the non-player person. A problem that this has is that it produces every match twice (once for Pintel as the first subject and Ragetti as the second, once the other way around); you could solve that by having the outer loop set a flag on each person that determines whether they’ve already been the first subject, like this:

[code]A person can be already checked.

Every turn:
now every person is not already checked;
repeat with first subject running through listener people in the location:
now first subject is already checked;
repeat with second subject running through listener people who are not already checked in the location:
if the origin of second subject is the origin of first subject and the origin of first subject is not null:
say “[First subject] and [second subject] come from the same work!”
[/code]

All this can probably be made simpler if it’s guaranteed that there will always be exactly two listeners in a room at once.

The relationship points thing is also tricky. You can’t actually give points to a relation–you can set a relation between Pintel and Rigetti, but you can’t define a three-way relation between Pintel, Rigetti, and a number. I think the easiest way to keep track of relationship strengths between characters will actually be to set up a table with columns for the people and a column for the relationship, kind of like this:

Table of Relationships first subject second subject relationship points Pintel Rigetti 0

(etc.; if you’re actually doing this it’s probably best to write a routine to automatically fill out the table’s initial values rather than write it all out by hand). Then it might be easier to have your loops go through the table instead of first finding the two people whose quips agree and then finding the row in the Table of Relationships where you have to change their relationship points.

On that last part, I have a bit of a personal addiction to putting tables in Inform code, so you might want to take it with a grain of salt when I advise that.

Hey matt w, thank you so much, that worked well!

This is what the code wound up looking like:


A person has some text called commStatus.  
A person has a table name called ResponseTable.

When play begins:
	now the commStatus of Lifesabre is "Undecided";
	now the commStatus of Allahkazam is "Undecided";
	now the commStatus of Darwin is "Undecided";

Definition: A person is a listener if it is not the player and it is not the convoHost.
A person can be already checked.

After reading a command when refreshComms is 0:
	now every person is not already checked;
	repeat with first subject running through listener people in the location:
		now first subject is already checked;
		repeat with second subject running through listener people who are not already checked in the location:
			if the commStatus of second subject is the commStatus of first subject:
				if the Table of Relationships is not empty:
					choose a row with a first friend of first subject in the Table of Relationships;
					Increase the relationship points entry by 10;
					choose a row with a first friend of second subject in the Table of Relationships;
					Increase the relationship points entry by 10;				
					choose a random row in the ResponseTable of first subject;
					let quipText be the Quip entry;
					let quipStatus be the QuipType entry;
					if quipStatus is "agree":
						now commStatus of the first subject is "Agree";
						say "[first subject] says: [quipText][line break]";
					if quipStatus is "disagree":
						now commStatus of the first subject is "Disagree";
						say "[first subject] says: [quipText][line break]";
					if quipStatus is "neutral":
						now commStatus of the first subject is "None";
						say "[first subject] says: [quipText][line break]";
					choose a random row in the ResponseTable of second subject;
					let quipTextTwo be the Quip entry;
					let quipStatusTwo be the QuipType entry;
					if quipStatusTwo is "agree":
						now commStatus of the second subject is "Agree";
						say "[second subject] says: [quipTextTwo][line break]";
					if quipStatusTwo is "disagree":
						now commStatus of the second subject is "Disagree";
						say "[second subject] says: [quipTextTwo][line break]";
					if quipStatusTwo is "neutral":
						now commStatus of the second subject is "None";
						say "[second subject] says: [quipTextTwo][line break]";

After reading a command when refreshComms is 0:
	now every person is not already checked;
	repeat with first subject running through listener people in the location:
		now first subject is already checked;
		repeat with second subject running through listener people who are not already checked in the location:
			if commStatus of the first subject is not commStatus of the second subject:
				if the Table of Relationships is not empty:
					choose a row with a first friend of first subject in the Table of Relationships;
					Decrease the relationship points entry by 15;
					choose a row with a first friend of second subject in the Table of Relationships;
					Decrease the relationship points entry by 15;				
					say "Oh no!  [first friend entry] and [second friend entry] disagree about things!  Their relationship status is [relationship points entry] [line break].";
					now refreshComms is 1;

After reading a command when refreshComms is 1:
	now every person is not already checked;
	repeat with first subject running through listener people in the location:
		now first subject is already checked;
		repeat with second subject running through listener people who are not already checked in the location:
			now commStatus of the first subject is "Undecided";
			now commStatus of the second subject is "Undecided";
			now refreshComms is 0;

After reading a command when refreshComms is 0:
	now every person is not already checked;
	repeat with first subject running through listener people in the location:
		now first subject is already checked;
		repeat with second subject running through listener people who are not already checked in the location:
			if commStatus of the first subject is commStatus of the second subject and commStatus of the first subject is not "Undecided":
				choose a row with a first friend of first subject in the Table of Relationships;
				say "[first friend entry] and [second friend entry] are in agreement!  Their relationship status is [relationship points entry] [line break].";

I think that’s all right. It’s messy as hell, i know.

The table solution at the bottom of your post is probably what i’ll go with. I’ve made a similar one in Inform and am working on figuring out the specifics.

Right now it prints everything out and increments the relationship variables the way it needs to, so i’m pretty happy. I’m a hell of a lot farther along than i was last night.

To answer your question Draconis:

The game i’m working on is about superheroes in a Phantom Zone-style jail. There’s a “Rec Yard” scene where they’re yelling things at each other, kind of in slow-motion (it’s a little bit of a weird setting- basically everyone with powers moves in slowmo, so their speech is truncated and broken). My idea with the bold/italics thing was that it would let the player easily see which quips were supposed to be agreement and which were disagreement.

Thanks for helping me guys.

Glad I could help! A couple of points:

–It looks like your commStatus takes on a few limited number of values. In this case, it’s probably better to use a kind of value for it rather than a text variable. So you could say:

CommStatus is a kind of value. The commStatuses are Undecided, Agree, Disagree, and None. A person has a commStatus.

Also, it looks to me as though your code for adjusting the Table of Relationships doesn’t actually affect relationships between the two people. If you’re adjusting the relationship between Darwin and Lifeshare, first you’ll choose a table row with first friend of Lifeshare, and then you’ll choose a table row with first friend of Darwin, but you won’t have chosen a row with both Darwin and Lifeshare (except by coincidence).
You want to do a two-column table lookup. There’s no built-in way to do that but you can adapt something like this. (I kind of feel like I should be able to change that so it’s completely general, with argument places for the table name, table column, etc., but not today… anyway if you have only one table you need to do a two-column lookup in, it should be OK to hardcode all that.)

Cool thanks. I have to read up on kinds some more. I haven’t really used them.

Damn, i didn’t know you could do that. My code increments the relationship points entry, but i think it does it in a very strange way.

I set the table up like this:


Table of Relationships
first friend	second friend	relationship points
Allahkazam	Lifesabre	20
Darwin	Lifesabre	0
Lifesabre	Darwin	0
Lifesabre	Allahkazam	20
Darwin	Allahkazam	0
Allahkazam	Darwin	0

I have all “combinations” of first subject and second subject in the table, so the code can grab for either one :laughing:

Glad there’s a better way to do it.

The stuff about kinds you need to know here is pretty accessible–check out §4.9 of the documentation for a start.

As for the table, I was thinking of a table that looks like yours. But I think the logic you had would often hit the wrong row. Say first subject is Allahkazam and second subject is Darwin. When you get here:

choose a row with a first friend of first subject in the Table of Relationships; Decrease the relationship points entry by 15; choose a row with a first friend of second subject in the Table of Relationships; Decrease the relationship points entry by 15;

what happens is that the first “choose a row” looks for the first row whose first friend entry is Allahkazam. That’s the first row. The the second “choose a row” looks for the next row whose first friend entry is Darwin, which is the second row (or maybe it goes back to the beginning to check–either way you get to the second row). So Allahkazam and Darwin both wind up getting their relationship points with Lifesabre docked!
You need to use a control phrase that checks whether a row has a first friend entry of Allahkazam and a second friend entry of Darwin before you choose the row. That’s what you can adapt from the code I linked.

I think i understand. So something like this:


friend-result-found is a truth state that varies.

To look up (first argument - a person) and (second argument - a person) in the Table of Relationships:
	let friend-result-found be false;
	repeat with N running from 1 to the number of rows in the Table of Relationships: 
		choose row N in the Table of Relationships;
		if the first friend entry is the first argument and the second friend entry is the second argument:
			now friend-result-found is true;
			if friend-result-found is true:
				choose a row with a first friend of first argument in the Table of Relationships;
				Decrease the relationship points entry by 15;
				choose a row with a first friend of second argument in the Table of Relationships;
				Decrease the relationship points entry by 15;				
				say "Oh no!  [first friend entry] and [second friend entry] disagree about things!  Their relationship status is [relationship points entry]. [line break]";
				now refreshComms is 1;

After reading a command when refreshComms is 0 and player is in The Yard:
	now every person is not already checked;
	repeat with first subject running through listener people in the location:
		now first subject is already checked;
		repeat with second subject running through listener people who are not already checked in the location:
			if commStatus of the first subject is not commStatus of the second subject:
				if the Table of Relationships is not empty:
					look up first subject and second subject in the Table of Relationships;

Is that mostly right? It seems to do the job.

That looks like it might work but is also a little overcomplicated.

One thing is that you’ve hardcoded the “Decrease the relationship points entry by 15” in the look up phrase. This doesn’t seem like a great idea–you might want to do something else with a relationship points entry, and anyway if you’re doing that you probably don’t want to call the phrase “look up.” Admittedly that is what I did in the linked code.

Another thing is that you have too many “choose a row” statements. Once you’ve chosen row N and made friend-result-found true, you should already be in the row where the first argument is first friend and the second argument is second friend. There won’t be a need to choose another row. I think that “choose a row with a first friend of first argument in the Table of Relationships” may still work because it starts from the row you’ve chosen and discovers the next row with a first friend of first argument, which is always going to be row N, but it seems to me that “choose a row with a first friend of second argument in the Table of Relationships” will go haywire (shouldn’t it be “second friend”)?

A final thing is that it looks like you’re using friend-result-found to effectively make sure the loop doesn’t do anything once it finds a result. You can actually use the special phrase “break” to do this (see §11.12 of the documentation). This just stops the loop, whether or not you’re actually done repeating it.

What I’d try would be to make the lookup phrase return a row number, which solves any worries about when “the chosen row” expires. Like this, though I haven’t checked it:

[code]To decide which number is the index of (first argument - a person) and (second argument - a person) in the Table of Relationships:
repeat with N running from 1 to the number of rows in the Table of Relationships:
choose row N in the Table of Relationships;
if the first friend entry is the first argument and the second friend entry is the second argument:
decide on N; [you don’t actually need a “break” here, because deciding on something automatically terminates the decide phrase]
decide on -1. [if nothing matched]

After reading a command when refreshComms is 0 and player is in The Yard:
now every person is not already checked;
repeat with first subject running through listener people in the location:
now first subject is already checked;
repeat with second subject running through listener people who are not already checked in the location:
if commStatus of the first subject is not commStatus of the second subject:
if the Table of Relationships is not empty:
let K be the index of the first subject and the second subject in the Table of Relationships [putting this in a temporary variable allows us to avoid doing the lookup twice]
unless K is -1: [if we found a row]
choose row K of the Table of Relationships;
decrease the relationship points entry by 15;
say “Oh no! [first subject] and [second subject] disagree about things! Their relationship status is [relationship points entry]. [line break]”[/code]

Hey matt w,

I see what you mean about it being over complicated (and using the showme command, it didn’t look like it was working anyway). Your method is working for me. Thanks a lot.