convert line ends
[canaan.git] / prj / cam / src / deepc / ai / dpcaipth.cpp
blob84d998434f9fdfd668982f96e0d034840a3528f6
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 // AI Pathfinding.
8 #include <dpcaipth.h>
10 #include <appagg.h>
12 #include <aiprops.h>
14 #include <autolink.h>
15 #include <doorphys.h>
16 #include <linkman.h>
17 #include <lockprop.h>
18 #include <propman.h>
19 #include <questapi.h>
20 #include <relation.h>
22 #include <dpcfrob.h>
23 #include <dpcprop.h>
25 #include <dbmem.h>
27 #define AIUsesDoors(obj) AIGetProperty(g_pAIUsesDoorsProperty, (obj), TRUE)
29 static IBoolProperty* g_pAIUsesDoorsProperty = NULL;
30 static IRelation* g_pSwitchLinkRelation = NULL;
32 ///////////////////////////////////////
34 void DPCAITermPathfinder(void)
36 SafeRelease(g_pAIUsesDoorsProperty);
39 ///////////////////////////////////////
41 STDMETHODIMP_(const char *) cDPCAIPathfinder::GetName()
43 return "DPC pathfinding component";
46 ////////////////////////////////////////
48 // A hack, for sure
51 inline BOOL DPCAIIsTripwire(ObjID objID)
53 return gPropTripFlags->IsRelevant(objID);
56 ////////////////////////////////////////
58 // Is this object a quest filter that should currently be "locking" this door?
59 // This is really a hack, but we assume that anything with the QB Name property on
60 // it is a QuestFilter.
63 BOOL cDPCAIPathfinder::QuestBlock(ObjID objID) const
65 const char* pQBName;
66 int QBVal;
67 int val;
69 // Start by checking for quest props on obj
70 if (!gPropQBName->Get(objID, &pQBName))
71 return FALSE;
72 gPropQBVal->Get(objID, &QBVal);
73 AutoAppIPtr(QuestData);
74 val = pQuestData->Get(pQBName);
75 if (val<=QBVal)
76 return TRUE;
77 return FALSE;
81 ///////////////////////////////////////
83 // Recursive search back along switch links to specified depth.
84 // This function returns the result in the openable parameter.
85 // It is defensive in the sense that it will return FALSE if any lock
86 // or unset quest bit is encountered in the search. It will only return
87 // true if it encounters a tripwire and no locks or unset quest bits.
88 // The actual function return value is used to specify whether to continue
89 // searching or not.
90 // The initial value of the openable parameter is assumed to be FALSE.
93 BOOL cDPCAIPathfinder::DoorOpenable(ObjID objID, int depth, BOOL& openable)
95 cAutoLinkQuery query(g_pSwitchLinkRelation, LINKOBJ_WILDCARD, objID);
97 if (depth<=0)
98 return TRUE;
100 while (!query->Done())
102 ObjID sourceID = query.GetSource();
103 int keypadCode;
105 // Check for impassable.
106 // Assume that anything with a keypad code property on it is a keypad
107 if (ObjSelfLocked(sourceID) || QuestBlock(sourceID) || g_pPropKeypadCode->Get(sourceID, &keypadCode))
109 openable = FALSE;
110 return FALSE;
112 if (DPCAIIsTripwire(sourceID))
113 openable = TRUE;
114 if ((depth>1) && !DoorOpenable(sourceID, depth-1, openable))
115 return FALSE;
116 query->Next();
118 return TRUE;
121 ///////////////////////////////////////
123 STDMETHODIMP_(BOOL) cDPCAIPathfinder::CanPassDoor(ObjID door)
125 BOOL openable;
127 // This is kind of stupid, but avoids ordering issues with init functions (& the AI)
128 if (g_pAIUsesDoorsProperty == NULL)
130 AutoAppIPtr(PropertyManager);
131 g_pAIUsesDoorsProperty = (IBoolProperty*)pPropertyManager->GetPropertyNamed("AI_UsesDoors");
132 Assert_(g_pAIUsesDoorsProperty);
134 if (g_pSwitchLinkRelation == NULL)
136 AutoAppIPtr(LinkManager);
137 g_pSwitchLinkRelation = pLinkManager->GetRelationNamed("SwitchLink");
138 Assert_(g_pSwitchLinkRelation);
141 if (!AIUsesDoors(GetID()))
142 return FALSE;
144 if (!IsDoor(door) || GetDoorStatus(door) == kDoorOpen || GetDoorStatus(door) == kDoorOpening)
145 return TRUE;
147 // just do 2 deep search for now
148 openable = FALSE;
149 DoorOpenable(door, 2, openable);
151 // The idea is that any unlocked, non-questy, closed door should be openable.
152 // In Shock, everything had to be hooked to a tripwire (tripped by either the AI or the player).
153 // This is no longer the case in DeepC. I'm leaving in support for Shock-style while allowing the Thief-style.
154 if (!openable &&
155 (GetDoorStatus(door) == kDoorClosed) &&
156 (!ObjSelfLocked(door)) &&
157 (!QuestBlock(door)))
159 return TRUE;
161 return openable;