View Issue Details

IDProjectCategoryView StatusLast Update
0003029The Dark ModAIpublic23.02.2012 16:19
Reportergrayman Assigned Tograyman  
PrioritynormalSeveritynormalReproducibilityalways
Status resolvedResolutionfixed 
Product VersionTDM 1.07 
Target VersionTDM 1.08Fixed in VersionTDM 1.08 
Summary0003029: AI should use an elevator if it's faster than walking
DescriptionThe AI pathing code only considers an elevator when there's no way to walk to the destination.

This ignores the case where taking the elevator would provide a quicker path.

Elevators should be considered along with walking paths when determining the quickest route.
TagsNo tags attached.

Activities

grayman

grayman

23.02.2012 16:19

administrator   ~0004345

The existing code for handling elevators only needed a few changes, mostly in the areas of interaction with the player and correcting a few problems when used by multiple AI.

1 - When an AI exits an elevator, the elevator queue makes the waiting AI nearest the elevator the new master. This prevents a cook (master) in the basement from yanking the elevator out from under a guard who's trying to step onto it on the 3rd floor. The guard should step onto the elevator and go where he needs to go. The cook might have to wait a bit longer, but "the needs of the many outweigh the needs of the few, or the one".

2 - Routing information is now sorted by travel time, instead of "hops". This puts the quickest path at the front of the routing info. A one-hop walking route could take longer than a 3-hop elevator route, thus the change. Also, hop-sorting can throw away the quickest of several elevator routes.

3 - Elevator travel time is 21*distance/speed. 21 is a fudge factor empirically determined by timing how long it takes an AI to walk the same distance, and the travel time the routing code uses for that walk distance.
15 is the most appropriate factor, but I had to raise it to 21 to get Outpost's first floor guard (the one who patrols into the chapel) to patrol properly. The current method of relying on the cluster->cluster travelTimes otherwise says that when walking from the chapel to the lobby, it's quicker to take the elevator. You walk out of the chapel, up the stairs to the upper hallway, then take the elevator down to the lobby. This is due to computing travel times between clusters by computing the travel times between the lowest-numbered AAS areas in those clusters. For the chapel, the lowest-numbered area is next to the lit candle under the balcony. For the lobby, it's the center of the upstairs hallway, because the two visportals on the stairs from the lobby to the upper floor don't create portals, making the lobby and the upstairs hallway a single cluster. By artificially making it more costly to use the elevator (15->21), I forced the walking route to have the shorter travel time.

4 - Changed SetupRoutesBetweenClusters() so it didn't initialize the same route multiple times, reaching the same result. (i.e. cluster 1->cluster 5 might calculate and save a sub-route through 2->5, but when later in the outermost loop it came time to fill in 2->5 itself, it was needlessly cleared and recalculated.)

5 - Route nodes now hold their travel time.

6 - A route now knows the total travel time of its route nodes.

7 - PushMove() and PopMove() twice instead of once when starting/finishing elevator handling. This solves the problem of an AI restoring the first saved move to get him to exit the elevator, but encountering a new elevator before he completes the exit. He's not allowed to handle two elevators at the same time, so the new elevator was getting tossed and not re-established in further pathing requests. The second PopMove() happens after he's walked off the elevator and is no longer handling it, guaranteeing that he sees and handles the new elevator. (i.e. The two elevators in the same test/elevator.map room.)

8 - Give an AI the closest of multiple good fetch buttons when he asks for one. "Closest" is determined by simple distance, not by travelTime.

9 - Lengthened the wait before activating the elevator when an AI "presses" a button so the elevator doesn't start moving before the right point in the animation. (The best solution is to have the animation notify the code of the exact frame, as we did with the relight animations, but I didn't go there.)

10 - Abort an AI's elevator exit if the elevator moves away from the station before the exit is complete. Ride it out so later he can do what he needs to to get to the right station. This could happen if the player fetches the elevator before the exit completes. (Surprise, surprise when the arriving AI busts the player.)

11 - A Builder with pauldrons could ride an elevator down, but not up. The elevator push code thought the Builder was blocked by his pauldrons, so it wouldn't move him up. The elevator and the Builder just sat there, though you could hear the elevator movement sound. The push code now ignores AI attachments.

12 – Abort an elevator task if the AI encounters a door. Door tasks and elevator tasks are both part of the Movement subsystem, and only one task can be active at a time, otherwise nasty things can happen.

Caveats

1 - We are at the mercy of the AAS compiler. Sometimes it behaves oddly in the neighborhood of a visportal, creating two portals side-by-side instead of one. Sometimes it doesn't create a portal where there's a visportal, connecting two or more leafs to make a larger leaf. This can wreak havoc with cluster-to-cluster travel times and cause AI to make what appear to be poor pathing decisions.

2 - Travel times into and out of a cluster at its portals are created using the lowest-numbered AAS area in the cluster, instead of an area that's near the 'center' of the cluster. This can sometimes cause AI to not use what appears to the player to be the shortest route. "Why's he going down the hall to use door A instead of using door B in front of him to get to a spot on the other side of B?!?" Well, it's because the travel time through the far door is less than that of the near door. I didn't look into this problem.

3 - I didn't address the problem of an AI fetching the elevator to use it as a bridge. (See Outpost's basement.) This could be made to work with a one-line change if the elevator station was not included in a neighboring hallway cluster, but was in its own. Since there's no guarantee that dmap will do that, even with correct visportaling, I didn't make the code change that would allow the AI to fetch an elevator to create a bridge. (If the elevator is already sitting at the station, the AI will use it like a bridge because he doesn't need elevator-handling to walk across it; he just uses a walking path. But if it's fetched to another floor while he's walking toward it, he'll turn away and make no attempt to fetch the elevator for his own use.) Perhaps an improved AAS compiler would let us revisit this in the future.

rev. 5292:

EAS.cpp
EAS.h
RouteInfo.cpp
RouteInfo.h
RouteNode.cpp
RouteNode.h
State.cpp
ChaseEnemyTask.cpp
HandleElevatorTask.cpp
HandleElevatorTask.h
PathCornerTask.cpp
AAS_pathing.cpp
AAS_routing.cpp
InteractionTask.cpp
AI.cpp
AI.h
Push.cpp
BinaryFrobMover.cpp
BinaryFrobMover.h
Mover.cpp
Mover.h
MultiStateMover.cpp
MultiStateMover.h
MultiStateMoverButton.cpp
MultiStateMoverButton.h
MultiStateMoverPosition.cpp
MultiStateMoverPosition.h


rev. 12642:

maps/test/elevator_108.map
maps/test/elevator1.map
maps/test/elevator2.map
maps/test/elevator3.map
tdm_game01.pk4

Issue History

Date Modified Username Field Change
22.02.2012 16:26 grayman New Issue
22.02.2012 16:26 grayman Status new => assigned
22.02.2012 16:26 grayman Assigned To => grayman
23.02.2012 16:19 grayman Note Added: 0004345
23.02.2012 16:19 grayman Status assigned => resolved
23.02.2012 16:19 grayman Resolution open => fixed
23.02.2012 16:19 grayman Fixed in Version => TDM 1.08