How do I restrict pushing specific items through specific doors in Inform 7 - inform7

I have a number of things I want to restrict from fitting through specific doors. So the chair is too big/heavy to carry but can be pushed through room to room in most cases. Except if the door is narrow. I can probably write specific code successfully to handle a specific case, but I want to handle this generically so I can have a number of bulky things and narrow doors.
The follow code functionally works, however the second noun ends up "nothing". I would like to use the name of the door in the direction of travel to respond to "push chair s" with the message "The chair is way too bulky to fit through the crack". Any ideas what I am doing wrong or another way of doing this?
A thing can be bulky. A thing is usually not bulky.
A bulky thing is usually pushable between rooms.
A door can be narrow. A door is usually not narrow.
A bulky, enterable supporter called the chair is in room1.
There is a narrow door called the crack. It is south of room1.
Before going with a bulky thing through a narrow door:
say "[The noun] is way too bulky to fit through [the second noun]." instead;

You can name the things in the rule preamble and use those names to print them in the rule.
Before going with a bulky thing (called the cargo) through a narrow door (called the obstacle):
say "[The cargo] is way too bulky to fit through [the obstacle]." instead.

Related

Inform7: Change a room's description depending on where the player came from

I'm pretty new to Inform and it seems like this shouldn't be too hard to do but I haven't yet found a way. I want to change a room's description based on where the player came from. Something along the lines of:
The Town Square is a room. "As you enter the small town square, [if yourself came from West]
the rising sun makes silhouettes of the roofs and spires to the East.[otherwise]your long
shadow strides before you as the Sun rises behind.[end if]"
What's the best way to go about this?
I found a reasonable solution:
The last location is a room that varies.
Orientation is a direction that varies.
Before going to anywhere, now the last location is the location of the player.
After going to anywhere:
now orientation is the best route from the last location to the location, using even locked doors;
continue the action.
The Town Square is a room. "As you enter the small town square, [if orientation is east]
the rising Sun makes silhouettes of the roofs and spires to the East.[otherwise if orientation is west]
your long shadow strides before you as the Sun rises behind.[end if]"
The "using even locked doors" modifier ensures this will work even if a door closes and locks behind the player. The solution does assume that the player has come via a reversible route, which may not always be the case e.g. if the player has teleported.

Handle traffic in 2D city builder

I´m creating a 2D isometric city building simulation and today I have kind of a "best practice" question without asking for specific code.
As in all city building games you are able to place building, roads and so on. The player is able to place building everywhere, no matter if it´s connected to a road or not. In addition to that there is one building (call it center building) all the buildings need to be connected with (by road).
I need to handle that without doing too many calculations which, breaks the FPS.
Right now I have a timer job for each building which checks if one of the surrounded tiles of a building is a road. That works fine, also for a lot of buildings since the check is simple.
But now I would like to check the connection to the center building. To check that it is necessary (in my opinion) to use something like a pathfinder, which checks if one of the surrounded tiles has a road connection to one of the surrounded tiles of the center building.
I can not check that frequently because this completely smashes the FPS down to 30 or lower. My idea was to fire an event if a road has been built or destroyed to "recalulate" the road connection. But there comes another problem...the player might destoy a road in the middle of the map and the buildings are really far away from each other so I need to find the involved buildings which also might take too much time.
My last idea is creating something like a timer queue and work through these items gradually, but before I keep using the trial and error method I would like to ask you for ideas.
Really looking forward to your ideas!
Yheeky
You could have each building store a list of tiles (a path) that connects it to the center building. Then when a tile is randomly destroyed by the player, you can have each building tested to see if it pathed through that road tile or not.
Alternatively you could have each road tile store which buildings require it, so when the tile is destroyed you have the buildings immediately throw flags. This could get quite messy though, but lends itself decently to background speed cleanup calls.
Both methods are quite messy. Perhaps you can make it a rule that the player can't place roads except next to other roads or next to the center building. Then when the player deletes a road tile, do a paint-style fill that destroys all of the disconnected roads. You can also periodically do a random check on tiles to see if they are illegally placed or not, but that should be unnecessary if you're careful.

How do I generate a waypoint map in a 2D platformer without expensive jump simulations?

I'm working on a game (using Game Maker: Studio Professional v1.99.355) that needs to have both user-modifiable level geometry and AI pathfinding based on platformer physics. Because of this, I need a way to dynamically figure out which platforms can be reached from which other platforms in order to build a node graph I can feed to A*.
My current approach is, more or less, this:
For each platform consider each other platform in the level.
For each of those platforms, if it is obviously unreachable (due to being higher than the maximum jump height, for example) do not form a link and move on to next platform.
If a link seems possible, place an ai_character instance on the starting platform and (within the current step event) simulate a jump attempt.
3.a Repeat this jump attempt for each possible starting position on the starting platform.
If this attempt is successful, record the data necessary to replicate it in real time and move on to the next platform.
If not, do not form a link.
Repeat for all platforms.
This approach works, more or less, and produces a link structure that when visualised looks like this:
linked platforms (Hyperlink because no rep.)
In this example the mostly-concealed pink ghost in the lower right corner is trying to reach the black and white box. The light blue rectangles are just there to highlight where recognised platforms are, the actual platforms are the rows of grey boxes. Link lines are green at the origin and red at the destination.
The huge, glaring problem with this approach is that for a level of only 17 platforms (as shown above) it takes over a second to generate the node graph. The reason for this is obvious, the yellow text in the screen centre shows us how long it took to build the graph: over 24,000(!) simulated frames, each with attendant collision checks against every block - I literally just run the character's step event in a while loop so everything it would normally do to handle platformer movement in a frame it now does 24,000 times.
This is, clearly, unacceptable. If it scales this badly at a mere 17 platforms then it'll be a joke at the hundreds I need to support. Heck, at this geometric time cost it might take years.
In an effort to speed things up, I've focused on the other important debugging number, the tests counter: 239. If I simply tried every possible combination of starting and destination platforms, I would need to run 17 * 16 = 272 tests. By figuring out various ways to predict whether a jump is impossible I have managed to lower the number of expensive tests run by a whopping 33 (12%!). However the more exceptions and special cases I add to the code the more convinced I am that the actual problem is in the jump simulation code, which brings me at long last to my question:
How would you determine, with complete reliability, whether it is possible for a character to jump from one platform to another, preferably without needing to simulate the whole jump?
My specific platform physics:
Jumps are fixed height, unless you hit a ceiling.
Horizontal movement has no acceleration or inertia.
Horizontal air control is allowed.
Further info:
I found this video, which describes a similar problem but which doesn't provide a good solution. This is literally the only resource I've found.
You could limit the amount of comparisons by only comparing nearby platforms. I would probably only check the horizontal distance between platforms, and if it is wider than the longest jump possible, then don't bother checking for a link between those two. But you might have done this since you checked for the max height of a jump.
I glanced at the video and it gave me an idea. Instead of looking at all platforms to find which jumps are impossible, what if you did the opposite? Try placing an AI character on all platforms and see which other platforms they can reach. That's certainly easier to implement if your enemies can't change direction in midair though. Oh well, brainstorming is the key to finding something.
Several ideas you could try out:
Limit the amount of comparisons you need to make by using a spatial data structure, like a quad tree. This would allow you to severely limit how many platforms you're even trying to check. This is mostly the same as what you're currently doing, but a bit more generic.
Try to pre-compute some jump trajectories ahead of time. This will not catch all use cases that you have - as you allow for full horizontal control - but might allow you to catch some common cases more quickly
Consider some kind of walkability grid instead of a link generation scheme. When geometry is modified, compute which parts of the level are walkable and which are not, with some resolution (something similar to the dimensions of your agent might be good starting point). You could also filter them with a height, so that grid tiles that are higher than your jump height, and you can't drop from a higher place on to them, are marked as unwalkable. Then, when you compute your pathfinding, as part of your pathfinding step you can compute when you start a jump, if a path is actually executable ('start a jump, I can go vertically no more than 5 tiles, and after the peak of the jump, i always fall down vertically with some speed).

Inform7: Working with properties of rooms

I'm very, very new to this language, and wrapping my head around "how to do things with stuff" is proving to be a very frustrating endeavor.
My goal here is to create a mechanic where certain rooms are dangerous, and become more dangerous the longer the player stays in them. If the player stays in a dangerous room for too long, a death scene is triggered.
I've got code that looks like this:
[The "danger rule"]
A room has a number called danger level. The danger level of a room is usually 0.
Definition: A room is dangerous if its danger level is 1 or more.
Definition: A room is deadly if its danger level is 9 or more.
Every turn (this is the increasing danger rule):
If the player is in a dangerous room:
Increase danger level by 1.
Every turn (this is the death by danger rule):
If the room is deadly:
do nothing.[Later...]
Every turn (this is the danger explanation rule):
say danger level.
[further down]
The Feeding Chamber is south of the dungeon."You enter a large, dimly lit room with straw on the floor, surrounded by various cages embedded in the wall.[line break]Blood spatters are all over the floor, and it looks as if there's been a fight recently". After going to the feeding chamber for the first time:
try looking;
say "It smells like grues around here. I would be careful if I were you..";
The Feeding Chamber has danger level 5.
I can't seem to figure out how to properly work with the "danger level of a room". The explanation rule I defined causes a runtime error when entering a dangerous room:
`*** Run-time problem P31: Attempt to use a property of the 'nothing' non-object: property danger level`
..And attempts to re-word the rule to something like the danger level of the room or the danger level of this room lead to perplexing compilation messages such as:
`In the sentence 'say the danger level of the room' , it looks as if you intend 'danger level of the room' to be a property, but 'a room' is not specific enough about who or what the owner is.`
What is the "right" way to reference properties of objects in this way?
The magic words here were "of the location". If we pretend that that this was another programming language for a moment, the way I was writing this was as if I was referring to a class "the room" rather than an instance of the class currently being referenced "the location".
The working rule is as follows:
Every turn while the player is in a dangerous room:
Increase danger level of the location by 1.
The trick is to give Inform enough information to know which particular thing you're referring to. The problematic sentence in the original question is perfectly valid english that a human could parse, but the computer needs a bit more help in determining what room we mean when we say "the room".

A* Pathfinding - closest to unwalkable destination

I already have an A* Implementation that works. The problem is that if you pick a destination that is unwalkable, no path is returned. I want to be able to get the 'closest' I can get.
The preferable option would be completely dynamic (not just checking the 8 tiles around the destination to try to find one). That way, even if they click an unwalkable tile surrounded by a huge square of unwalkable tiles, it will still get as close as it can.
While the simple answers provided here MIGHT be sufficient enough, I think it depends on your game type and what you're trying to achieve.
For example, take this play field (sorry I'm reusing the same software I used to show you the fog of war :)) :
As you can see, an Angry Chicken is blocking the path between the left side and the right side. The Angry Chicken could be anything... if it's a static obstacle, then going with the lowest h node might be enough, but if it's a dynamic object (like a locked door, draw bridge, etc...) the following examples might help you find out how you want to solve your problem.
If we set the destination for our Hero on the other side
We need to think what we want the path to be, since obviously we can't reach it. Using a standard heuristic like manhattan distance or euclidian distance, you will get this result:
Which might be good enough, but if there's any way our little Hero could interact with the chicken to pass, it doesn't make sense at all, what you want is this
How can you do this? Well, an easy way to do this is to pathfind on hierarchical graphs. This sounds complicated but it isn't. First, you want to be able to build a new set of high level nodes and edges that will contain multiple grid nodes (or other representation, wouldn't change a thing)
As you can see, we now have a right blue node and a left red node. The arrow represents the edge between the two nodes. How to build this graph you ask? It's easy, simply start from an open node, expand all of its neighbors and add them to a high level node, when you're done, open the dynamic nodes that could lead to another part of the graph and do the same.
Now, when you ask for a path from our Hero to the red X, you first do the pathfinding on the high level... is there a way from blue node to red node? Yes! Through the chicken.
You can now easily know how to navigate on the blue side by going to the edge that will allow you to cross, which is the chicken.
If it was just a plain wall, you could determine very quickly, by visiting a single node, that there is NO way to reach on the other side and then handle it the way you want, possibly still performing an A* and returning the lowest h node.
You could keep a pointer which holds a tile with the lowest h-value, then if no path is returned simply generate a path to the tile you're holding onto instead.

Resources