"in one turn from now" acting strange

Hey again everyone! thanks for the help so far, it’s really great! Unfortunately i have already run into a new problem, that i don’t seem to be able to fix. I am really trying to overcome these issues on my own, but Inform 7 is just such a strange (but great) coding language that i find it hard to master without the guidance of experienced users :slight_smile:

I’m having some code that executes perfectly but doesn’t seem to work out the way it’s intended to. I have tried all sorts of combinations, and feel like i have come very far, but this on is just very weird to me.

What im trying to do is to make an attack system, where the monster firstly will spot the player, and then after a turn attack the player.

[code]
A person can be seen or unseen. A person is usually unseen.

Every turn:
if the player is unseen begin;
if a monster can see the player begin;
say “You are spotted!”;
the player is seen in one turn from now;
end if;
end if.

At the time when the player is seen:
now the player is seen;

Every turn:
repeat with madman running through people begin;
if madman is hostile begin;
if the player is seen begin;
try madman attacking the player;
end if;
end if;
if madman is dead, now madman is docile;
end repeat.[/code]

That is the code and it compiles without error. The thing is that for some reason this combination of this piece of code never executes:

At the time when the player is seen:
	now the player is seen;

Which means that the monster never commences to attack, and just reads “You are spotted!” every turn repeatedly.
but if i remove the if statement in the “madman” sequence, then that piece of code executes just fine (only saying “you are spotted!” once).

Every turn:
	repeat with madman running through people begin;
		if madman is hostile begin;
			try madman attacking the player;
		end if;
	if madman is dead, now madman is docile;
	end repeat.

which makes it say “You are spotted!” only once, but makes the monster attack right away (the action we are trying to delay with only one turn).

There’s one thing I run into with flags (unseen vs. seen) that I don’t run into with variables: on and off states. I’m not sure if this is your problem, but this might get you toward a solution.

Every turn:
	if the player is unseen begin;
		if a monster can see the player begin;
			say "You are spotted!";
                        Now the player is not unseen; [unset the "unseen" flag]
                        Now the player is seen; 
		end if;
	end if.

For the attacking in the next turn, I would set a variable.

A monster has a number called attack_offset.

[Then, add the offset]

Every turn:
	if the player is unseen begin;
		if a monster can see the player begin;
			say "You are spotted!";
                        Now the player is not unseen; [unset the "unseen" flag]
                        Now the player is seen; 
                        Now the attack_offset of a monster is 1; [set the offset on first seen]
		end if;
	end if.

Every turn:
	repeat with madman running through people begin;
		if madman is hostile begin;
			if the player is seen begin;
                                 if the attack_offset of madman is 0:
			                try madman attacking the player;
                                 Otherwise:
                                        Now the attack_offset of a madman is 0; [this puts in the delay of one turn]
			end if;
		end if;
	if madman is dead, now madman is docile;
	end repeat.

Maybe not the most elegant (and untested), but the variable will create the turn offset. Unsetting the “unseen” flag might do the trick with your current code, though.

                        Now the player is not unseen; [unset the "unseen" flag]
                        Now the player is seen; 

That’s not necessary.

Okay – that makes sense. There’s an “or” between seen or unseen that turns off the opposite state. That’s useful to know.

@craftian
your code gives me this problem:

Problem. The rule or phrase definition 'Every turn'   seems to use both ways of grouping phrases together into 'if', 'repeat' and 'while' blocks at once. Inform allows two alternative forms, but they cannot be mixed in the same definition. 

 One way is to end the 'if', 'repeat' or 'while' phrases with a 'begin', and then to match that with an 'end if' or similar. ('Otherwise' or 'otherwise if' clauses are phrases like any other, and end with semicolons in this case.) You use this begin/end form here, for instance - 'repeat with madman running through people begin'  . 

 The other way is to end with a colon ':' and then indent the subsequent phrases underneath, using tabs. (Note that any 'otherwise' or 'otherwise if' clauses also have to end with colons in this case.) You use this indented form here - 'if the attack_offset of madman is 0'  .

which made me modify the code after the other kind of grouping giving me this outcome:

A person can be seen or unseen. A person is usually unseen.
A monster has a number called attack_offset.

Every turn:
	if the player is unseen begin;
		if a monster can see the player begin;
			say "You are spotted!";
			the player is seen in one turn from now;
			Now the attack_offset of a monster is 1; 
		end if;
	end if.

At the time when the player is seen:
	now the player is seen;

Every turn:
	repeat with madman running through people:
		if madman is hostile:
			if the player is seen:
				if the attack_offset of madman is 0:
					try madman attacking the player;
				Otherwise:
					Now the attack_offset of a madman is 0;
	if madman is dead: 
		now madman is docile.

but this gave me alot of new errors that i don’t understand why i get;

Problem. In the sentence 'Now the attack_offset of a monster is 1'  , it looks as if you intend 'attack_offset of a monster' to be a property, but 'a monster' is not specific enough about who or what the owner is. 

 Sometimes this mistake is made because Inform mostly doesn't understand the English language habit of referring to something indefinite by a common noun - for instance, writing 'change the carrying capacity of the container to 10' throws Inform because it doesn't understand that 'the container' means one which has been discussed recently.

I was trying to match this phrase:

 now (attack_offset of a monster is 1 - a phrase) 

I recognised:

attack_offset of a monster is 1 = a condition



--------------------------------------------------------------------------------

Problem. You wrote 'Now the attack_offset of a madman is 0'  : but this is a phrase which I don't recognise, possibly because it is one you meant to define but never got round to, or because the wording is wrong (see the Phrasebook section of the Index to check). Alternatively, it may be that the text immediately previous to this was a definition whose ending, normally a full stop, is missing?

I was trying to match this phrase:

 now (attack_offset of a madman is 0 - a phrase) 

But I didn't recognise 'attack_offset of a madman is 0'.



--------------------------------------------------------------------------------

Problem. In the sentence 'if madman is dead'  , I was expecting to read a condition, but instead found some text that I couldn't understand - 'madman is dead'.

I was trying to match this phrase:

 if (madman is dead - a condition): 

But I didn't recognise 'madman is dead'.



--------------------------------------------------------------------------------

Problem. You wrote 'now madman is docile'  : again, this is a phrase which I don't recognise.

I was trying to match this phrase:

 now (madman is docile - a phrase) 

But I didn't recognise 'madman is docile'.

it understood these phrases perfectly before? why not now?

Do you have monster class defined? As in: “a monster is a kind of person”, or something like it?

Each time the attack_offset is applied, it will be applied to the specific monster from the monster class (as defined above.) It looks like Inform isn’t applying the variable to a specific monster, and it’s throwing it for a loop. I would try something like this (not tested), as a way of applying the variable to a specific monster in the monster class.

Every turn:
	if the player is unseen:
                Repeat with m running through monsters in the location of the player: 
		       if m can see the player:
			      say "You are spotted!";
			      [ the player is seen in one turn from now;]
			      Now the attack_offset of m is 1; 

That syntax is slightly different, but it’s going to hone in on the specific monster you want to apply the variable to. The other upside of this is that you can have multiple monsters who both have and haven’t seen the player – the attack_offset variable is applied to the specific one that’s spotted the player.

It looks like there’s one other problem in this code – if the tabs in your code sample are the same in your actual code:

Every turn: repeat with madman running through people: if madman is hostile: if the player is seen: if the attack_offset of madman is 0: try madman attacking the player; Otherwise: Now the attack_offset of madman is 0; if madman is dead: now madman is docile.

The “if madman is dead” code has to line up with the “if madman is hostile”. Madman is the temporary variable for your loop, and doesn’t exist outside the loop. If the code that references it is on the same line as the repeat code, then you’re outside the loop.

Also, one more thing that might be causing a problem – I removed the “a” next to “a madman” in your loop. “Madman” is the temporary variable. I’d use something easier, like “m”, which is easier to spot that it’s a temporary variable, and not a class. That might be why you got the error on that code.

Finally, if you use the monster class as a kind of person, and the attack_offset is applied to the monster class, you’ll have to “repeat through monsters”, instead of “repeat through people”, to apply the variable to a monster.

@craftian

Yes, “A monster is a kind of person” is defined.

i got this error now, which doesn’t make alot of sense to me either:

Problem. You wrote 'Now the attack_offset of m is 1'  : but this seems to say that a thing is a value, like saying 'the chair is 10'.

with this code:

A person can be seen or unseen. A person is usually unseen.
A monster has a number called attack_offset.

Every turn:
	if the player is unseen begin:
		Repeat with m running through monsters in the location of the player:
			if m can see the player begin:
				say "You are spotted!".
				[the player is seen in one turn from now.]
				Now the attack_offset of m is 1.

At the time when the player is seen:
	now the player is seen;

Every turn:
	repeat with madman running through monsters:
		if madman is hostile:
			if the player is seen:
				if the attack_offset of madman is 0:
					try madman attacking the player;
				Otherwise:
					Now the attack_offset of madman is 0;
	if madman is dead: 
		now madman is docile.

also tried to change the “attack_offset” to be a number applied to “m”, which didn’t work, just gave me the same error. I don’t understand that error, it doesn’t make any references and it’s pretty clearly defined that we aren’t trying to say “monster is 10” but that a value of the monster is now “1”.

This one’s easy:

Every turn:
	if the player is unseen begin:
		Repeat with m running through monsters in the location of the player:
			if m can see the player begin:
				say "You are spotted!"; [has to be a semicolon to keep going with the loop.]
				[the player is seen in one turn from now.]
				Now the attack_offset of m is 1.

I thought of one thing, too. You might one to apply the seen vs. unseen variable to monsters, so that when a monster sees the player, it acts on its own. Like this:


a monster can be aware or unaware. a monster is usually unaware. [vs seen or unseen for the player.]

Every turn:
	Repeat with m running through monsters in the location of the player:
                if m is aware, next; [skip out of this loop if m has seen the player]
		if m can see the player begin:
			say "You are spotted!"; [has to be a semicolon to keep going with the loop.]
			[the player is seen in one turn from now.]
			Now the attack_offset of m is 1;
                        Now the m is aware;

Something like that will make monsters that have seen the player attack, while others that haven’t seen the player won’t attack.

You can’t use semicolon in a colon grouping phrase :confused:

Problem. The phrase or rule definition ‘Every turn’ is written using the ‘colon and indentation’ syntax for its 'if’s, 'repeat’s and 'while’s, where blocks of phrases grouped together are indented one tab step inward from the ‘if …:’ or similar phrase to which they belong. But the phrase ‘if m can see the player begin’ , which ought to begin a block, is immediately followed by ‘say “You are spotted!”’ at the same or a lower indentation, so the block seems to be empty - this must mean there has been a mistake in indenting the phrases.


Problem. The phrase or rule definition ‘Every turn’ is written using the ‘colon and indentation’ syntax for its 'if’s, 'repeat’s and 'while’s, where blocks of phrases grouped together are indented one tab step inward from the ‘if …:’ or similar phrase to which they belong. But the tabs here seem to be misaligned, and I can’t determine the structure. The first phrase going awry in the definition seems to be ‘if m is aware, next’ , in case that helps.

That error usually means that your indenting is off. I don’t know how accurate the “code” tag is here – make sure that the tab indents are right and that error should probably go away.

The loop solution is way more convoluted than it needs to be.

Every turn: if the player is unseen and a monster (called the enemy) can see the player begin; say "You are spotted!"; now the player is seen; now the attack_offset of the enemy is 1; end if.
The reason it didn’t work before is that there are (potentially) multiple monsters so setting the attack_offset of “a monster” wasn’t specific enough – Inform can’t make the connection between the monster mentioned in the if condition and “a monster” mentioned later in the code, unless you name the monster and then refer to that specific one.

You can also get rid of the if line completely:

Every turn when the player is unseen and a monster (called the enemy) can see the player: say "You are spotted!"; now the player is seen; now the attack_offset of the enemy is 1.
This way you don’t need to worry about mixing the begin-end style and the indentation style of formatting blocks, which is what causes the latest error.

Yeah – that’s a much tighter loop. I would still recommend:

Every turn when the player is unseen and a monster (called the enemy) can see the player:
    say "You are spotted!";
    [now the player is seen; ]
    now the enemy is aware;
    now the attack_offset of the enemy is 1.

This puts the variable on each individual enemy, rather than the player. Unless you want to have all enemies attack once the player is seen, in which case, the variable on the player works.

Oops – edit:

This loop only works if the player is unseen. If the logic is going to apply to enemies in the location, the “player is unseen” variable has to be dropped. Would something like this work?

Every turn when a monster (called the enemy) can see the player:
    [I have to put an IF statement in, no other way I know how to do it:]
    If the enemy is unaware:
       say "You are spotted!";
       [now the player is seen; ]
       now the enemy is aware;
       now the attack_offset of the enemy is 1.

Alternatively, if you could put the unaware / aware switch in the opening loop, you could get rid of the if statement.

I remember having huge problems with this in TRANSPARENT. My intention was to have a monster that has a high chance of killing the player if it could “see” the player. I even lit the monster to make sure darkness wouldn’t interfere. It worked only sporadically. I’m sure my code was tangled, but I wonder if it’s possible to have too many “every turn when…” rules.

Same weird sort of issue in my WIP: characters scheduled to move every turn were frozen until encountered by the player, then they would move. I wonder if it’s a weird part of Epistemology where unseen things don’t exist and won’t move.

No. It might make the game slow, but they won’t stop working.

(Unless you put a “stop the action” phrase in one. That cuts off the every-turn rulebook immediately. Don’t do that.)

I’m working on similar stuff – having creatures move around with their own A.I. scripts on each player movement, with a lot of the time being in another location, or out of play in a holding room. If the enemies are frozen, there has to be some sort of variable or flag in the loop that’s triggering on the player being in the location. Otherwise, it should work every turn.

Okay everyone, i got working finally with this piece of code:

A monster has a number called attack_offset.
A monster can be aware or unaware. a monster is usually unaware.

Every turn when a monster (called the enemy) can see the player:
	If the enemy is unaware:
		say "You are spotted!";
		now the enemy is aware;
		now the attack_offset of the enemy is 1.


Every turn:
	repeat with madman running through monsters:
		if madman is hostile:
			if madman is aware:
				if the attack_offset of madman is 0:
					try madman attacking the player;
				Otherwise:
					Now the attack_offset of madman is 0;
		if madman is dead: 
			now madman is docile.

This version also works with seperate monsters, and is not global on the player :slight_smile:

Thanks for the help, i really appreciate it!