convert line ends
[canaan.git] / prj / cam / src / engfeat / quest.cpp
blobf83008ef3f5b8d1eedf477ad9b22fedb0b2dced9
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 // $Header: r:/t2repos/thief2/src/engfeat/quest.cpp,v 1.14 1999/08/31 17:42:29 Justin Exp $
8 #include <questapi.h>
9 #include <quesscpt.h>
11 #include <scrptapi.h>
13 #include <hashset.h>
14 #include <hshsttem.h>
16 #include <hashpp.h>
17 #include <hshpptem.h>
19 #include <dlist.h>
21 #include <appagg.h>
22 #include <aggmemb.h>
24 #include <creatext.h>
26 #include <iobjsys.h>
27 #include <objtype.h>
28 #include <objdef.h>
29 #include <objnotif.h>
30 #include <listset.h>
31 #include <lststtem.h>
33 #include <str.h>
35 #include <netmsg.h>
37 #ifndef SHIP
38 #include <mprintf.h>
39 #endif
41 // Include these absolutely last
42 #include <dbmem.h>
43 #include <initguid.h>
44 #include <questiid.h>
46 //------------------------------------------------------------
47 // Quest Data
50 class cObjList: public cSimpleListSet<ObjID>
54 // List for storing pointers to data nodes for each object that subscribes to data change messages
55 class cQuestDataNode;
57 typedef cSimpleDList<cQuestDataNode*> cQuestNodeList;
59 // Hash set stuff
60 class cQuestDataNode
62 public:
63 cStr m_pName;
64 int m_value;
65 eQuestDataType m_type;
66 cObjList m_subscriberList;
68 cQuestDataNode(const char *pName, eQuestDataType type):
69 m_pName(pName), m_type(type), m_value(0) {};
71 STDMETHOD(SendMsgs)(int oldValue) const;
74 // The actual data hash
75 class cQuestDataHash: public cStrIHashSet<cQuestDataNode*>
77 virtual tHashSetKey GetKey(tHashSetNode p) const
79 return (tHashSetKey)(const char*)((cQuestDataNode*)p)->m_pName;
83 // Object->data node hash for msg subscriptions
84 typedef cHashTableFunctions<ObjID> cObjIDHashFunctions;
85 typedef cHashTable<ObjID, cQuestNodeList*, cObjIDHashFunctions> cQuestSubscribeHash;
87 class cQuestData;
89 //------------------------------------------------------------
90 // Forward declare the iterator class
92 class cQuestDataIter : public cCTUnaggregated<IQuestDataIter,&IID_IQuestDataIter,kCTU_Default>
94 private:
95 tHashSetHandle m_handle;
96 cQuestDataNode *m_pNode;
97 const cQuestDataHash *m_pHash;
98 eQuestDataType m_type;
100 void Match(void)
102 while ((m_pNode != NULL) && (m_pNode->m_type != m_type))
104 m_pNode = m_pHash->GetNext(m_handle);
108 public:
110 cQuestDataIter(const cQuestDataHash *pHash, eQuestDataType type):
111 m_pNode(pHash->GetFirst(m_handle)),
112 m_pHash(pHash),
113 m_type(type)
115 Match();
118 STDMETHOD_(BOOL,Done)(void) {return (m_pNode == NULL);}
119 STDMETHOD(Next)(void) {if (m_pNode != NULL) m_pNode = m_pHash->GetNext(m_handle); Match(); return S_OK;}
121 STDMETHOD_(const char*,Name)() {if (m_pNode != NULL) return (const char*)(m_pNode->m_pName); else return NULL;};
122 STDMETHOD_(int,Value)() {if (m_pNode != NULL) return m_pNode->m_value; else return 0;};
127 //------------------------------------------------------------
128 // Now the real quest data class
130 class cQuestData: public cCTDelegating<IQuestData>,
131 public cCTAggregateMemberControl<kCTU_Default>
133 static sRelativeConstraint gConstraints[];
135 public:
136 cQuestData(IUnknown* pOuter)
137 : m_filter(NULL)
139 MI_INIT_AGGREGATION_1(pOuter, IQuestData, kPriorityNormal, gConstraints);
142 STDMETHOD(Init)()
144 sObjListenerDesc objListenerDesc = {&cQuestData::ObjListener,};
146 AutoAppIPtr(ObjectSystem);
147 m_listenerHandle = pObjectSystem->Listen(&objListenerDesc);
149 m_pCreateMsg = new cNetMsg(&gm_CreateMsgDesc, this);
150 m_pSetMsg = new cNetMsg(&gm_SetMsgDesc, this);
152 return S_OK;
155 STDMETHOD(End)()
157 DeleteAll();
158 delete m_pCreateMsg;
159 delete m_pSetMsg;
160 return S_OK;
163 STDMETHOD(Create)(const char *pName, int value, eQuestDataType type);
164 STDMETHOD(Set)(const char *pName, int value);
165 STDMETHOD_(int, Get)(const char *pName);
166 STDMETHOD_(BOOL, Exists)(const char *pName)
168 return (m_nameHash.Search(pName)!=NULL);
170 STDMETHOD(Delete)(const char *pName);
171 STDMETHOD_(IQuestDataIter*, Iter)(eQuestDataType type)
173 return (IQuestDataIter*)(new cQuestDataIter(&m_nameHash, type));
175 STDMETHOD(DeleteAll)(void);
176 STDMETHOD(DeleteAllType)(eQuestDataType type);
178 STDMETHOD_(BOOL, Save)(QuestMoveFunc moveFunc, eQuestDataType type);
179 STDMETHOD_(BOOL, Load)(QuestMoveFunc moveFunc, eQuestDataType type);
181 STDMETHOD(SubscribeMsg)(ObjID objID, const char *pName, eQuestDataType type);
182 STDMETHOD(UnsubscribeMsg)(ObjID objID, const char *pName);
184 static void ObjListener(ObjID objID, eObjNotifyMsg msg, void *data);
185 STDMETHOD(ObjDeleteListener)(ObjID objID);
187 STDMETHOD(UnsubscribeAll)();
189 #ifndef SHIP
190 STDMETHOD(ObjSpewListen)(ObjID objID);
191 #endif
193 STDMETHOD(Filter)(QuestFilterFunc filter, void *pClientData);
195 // Internal methods that need to get called from network callbacks:
196 STDMETHOD(doCreate)(const char *pName, int value, eQuestDataType type);
197 STDMETHOD(doSet)(const char *pName, int value);
199 private:
201 tObjListenerHandle m_listenerHandle;
202 cQuestDataHash m_nameHash;
203 cQuestSubscribeHash m_subscriberHash;
204 QuestFilterFunc m_filter;
205 void *m_pClientData;
207 // Network messages:
208 static sNetMsgDesc gm_CreateMsgDesc;
209 cNetMsg *m_pCreateMsg;
210 static sNetMsgDesc gm_SetMsgDesc;
211 cNetMsg *m_pSetMsg;
214 //////////
216 // Network dispatching stuff
219 static void dispatchCreate(const char *pName,
220 int value,
221 eQuestDataType type,
222 void *pQuestData)
224 ((cQuestData *) pQuestData)->doCreate(pName, value, type);
227 sNetMsgDesc cQuestData::gm_CreateMsgDesc = {
228 kNMF_Broadcast,
229 "QuesCreate",
230 "Create Quest Data",
231 NULL,
232 dispatchCreate,
233 {{kNMPT_String},
234 {kNMPT_Int},
235 {kNMPT_Int},
236 {kNMPT_End}}
239 static void dispatchSet(const char *pName,
240 int value,
241 void *pQuestData)
243 ((cQuestData *) pQuestData)->doSet(pName, value);
246 sNetMsgDesc cQuestData::gm_SetMsgDesc = {
247 kNMF_Broadcast,
248 "QuesSet",
249 "Set Quest Data",
250 NULL,
251 dispatchSet,
252 {{kNMPT_String},
253 {kNMPT_Int},
254 {kNMPT_End}}
258 sRelativeConstraint cQuestData::gConstraints[] =
260 { kConstrainAfter, &IID_IObjectSystem },
261 { kNullConstraint },
264 STDMETHODIMP cQuestDataNode::SendMsgs(int oldValue) const
267 AutoAppIPtr(ScriptMan);
269 cObjList::cIter iter;
270 for (iter = m_subscriberList.Iter(); !iter.Done(); iter.Next())
272 sQuestMsg msg(iter.Value(), m_pName, oldValue, m_value);
273 pScriptMan->SendMessage(&msg);
275 return S_OK;
278 STDMETHODIMP cQuestData::Create(const char *pName, int value, eQuestDataType type)
280 m_pCreateMsg->Send(OBJ_NULL, pName, value, type);
281 return doCreate(pName, value, type);
284 STDMETHODIMP cQuestData::doCreate(const char *pName, int value, eQuestDataType type)
286 cQuestDataNode *pNode;
287 int oldValue;
289 if ((pNode = m_nameHash.Search((char*)pName)) != NULL)
291 oldValue = pNode->m_value;
292 pNode->m_value = value;
293 if (pNode->m_type != type)
295 if (pNode->m_type != kQuestDataUnknown)
296 Warning(("Changing type of quest data item %s\n", pName));
297 pNode->m_type = type;
300 else
302 pNode = new cQuestDataNode(pName, type);
303 pNode->m_value = value;
304 m_nameHash.Insert(pNode);
305 oldValue = 0;
307 pNode->SendMsgs(oldValue);
308 return S_OK;
311 STDMETHODIMP cQuestData::Set(const char *pName, int value)
313 m_pSetMsg->Send(OBJ_NULL, pName, value);
314 return doSet(pName, value);
317 STDMETHODIMP cQuestData::doSet(const char *pName, int value)
319 cQuestDataNode *pNode;
321 if ((pNode = m_nameHash.Search((char*)pName)) == NULL)
322 return Create(pName, value, kQuestDataCampaign);
324 int oldValue = pNode->m_value;
325 if (m_filter)
327 if (!m_filter(pName, oldValue, value))
328 return S_FALSE;
331 pNode->m_value = value;
332 pNode->SendMsgs(oldValue);
333 return S_OK;
336 STDMETHODIMP_(BOOL) cQuestData::Get(const char *pName)
338 cQuestDataNode *pNode;
340 if ((pNode = m_nameHash.Search(pName)) != NULL)
341 return pNode->m_value;
342 return 0;
345 STDMETHODIMP cQuestData::SubscribeMsg(ObjID objID, const char *pName, eQuestDataType type)
347 cQuestDataNode *pQuestNode;
349 if ((pQuestNode = m_nameHash.Search(pName)) == NULL)
351 // if this quest item doesn't exist, create and set to zero
352 Create(pName, 0, type);
353 pQuestNode = m_nameHash.Search(pName);
356 // add the data to the list
357 if (!pQuestNode->m_subscriberList.AddElem(objID))
358 return S_FALSE; // already subscribed
360 cQuestNodeList *pSubscribedList;
361 // add to the subscriber hash
362 if (!m_subscriberHash.Lookup(objID, &pSubscribedList))
364 pSubscribedList = new cQuestNodeList;
365 m_subscriberHash.Set(objID, pSubscribedList);
367 pSubscribedList->Append(pQuestNode);
369 return S_OK;
372 STDMETHODIMP cQuestData::UnsubscribeMsg(ObjID objID, const char *pName)
374 cQuestDataNode* pQuestNode = m_nameHash.Search(pName);
375 if (pQuestNode == NULL)
376 return S_FALSE;
378 // remove from subscriber list
379 if (!pQuestNode->m_subscriberList.RemoveElem(objID))
380 return S_FALSE;
382 BOOL found = FALSE;
383 cQuestNodeList *pSubscribedList;
385 // remove from subscriber hash
386 if (m_subscriberHash.Lookup(objID, &pSubscribedList))
388 cQuestNodeList::cIter iter;
389 for (iter = pSubscribedList->Iter(); !iter.Done(); iter.Next())
391 cQuestDataNode* pQuestNode = iter.Value();
392 if (strcmp(pQuestNode->m_pName,pName) == 0)
394 pSubscribedList->Remove(&iter.Node());
395 break;
399 // if the list is now empty... get rid of it
400 if (pSubscribedList->GetFirst() == NULL)
402 m_subscriberHash.Delete(objID);
403 delete pSubscribedList;
406 return S_OK;
409 STDMETHODIMP cQuestData::UnsubscribeAll()
411 tHashSetHandle hnd;
412 cQuestDataNode* node;
414 // Clear all subscriber lists
415 for (node = m_nameHash.GetFirst(hnd); node != NULL; node = m_nameHash.GetNext(hnd))
416 node->m_subscriberList.RemoveAll();
418 cQuestSubscribeHash::cIter iter;
419 for (iter = m_subscriberHash.Iter(); !iter.Done(); iter.Next())
421 cQuestNodeList* pSubList = iter.Value();
422 delete pSubList;
425 m_subscriberHash.Clear();
427 return S_OK;
431 STDMETHODIMP cQuestData::Delete(THIS_ const char *pName)
433 cQuestDataNode *pNode = m_nameHash.Search(pName);
435 if (!pNode)
436 return S_FALSE;
438 // deal with listeners
439 cObjList::cIter iter = pNode->m_subscriberList.Iter();
440 for (; !iter.Done(); iter.Next())
441 UnsubscribeMsg(iter.Value(),pName);
443 m_nameHash.Remove(pNode);
444 delete pNode;
445 return S_OK;
448 STDMETHODIMP cQuestData::DeleteAll(void)
450 tHashSetHandle handle;
451 cQuestDataNode *pNode;
453 pNode = m_nameHash.GetFirst(handle);
454 for (; pNode != NULL; pNode = m_nameHash.GetNext(handle))
455 Delete(pNode->m_pName);
456 return S_OK;
459 STDMETHODIMP cQuestData::DeleteAllType(eQuestDataType type)
461 tHashSetHandle handle;
462 cQuestDataNode *pNode;
464 pNode = m_nameHash.GetFirst(handle);
465 for (; pNode != NULL; pNode = m_nameHash.GetNext(handle))
466 if (pNode->m_type == type)
467 Delete(pNode->m_pName);
468 return S_OK;
471 STDMETHODIMP_(BOOL) cQuestData::Save(QuestMoveFunc moveFunc, eQuestDataType type)
473 tHashSetHandle handle;
474 int len;
475 cQuestDataNode *pNode;
477 pNode = m_nameHash.GetFirst(handle);
478 while (pNode != NULL)
480 if ((pNode->m_type == type) || ((pNode->m_type == kQuestDataUnknown) && (type == kQuestDataMission)))
482 len = strlen(pNode->m_pName)+1;
483 moveFunc((void*)&len, sizeof(int), 1);
484 moveFunc((void*)(const char*)pNode->m_pName, sizeof(char), len);
485 moveFunc((void*)&(pNode->m_value), sizeof(int), 1);
487 pNode = m_nameHash.GetNext(handle);
489 return S_OK;
492 STDMETHODIMP_(BOOL) cQuestData::Load(QuestMoveFunc moveFunc, eQuestDataType type)
494 int len;
495 int num;
496 int value;
498 while ((num = moveFunc((void*)&len, sizeof(int), 1)) == sizeof(int))
500 // Alloc a string of size len, bound within the scope of this block
501 cStr name("",len);
502 char* pName = (char*)(const char*)name;
504 if ((num = moveFunc((void*)pName, sizeof(char), len)) != len*sizeof(char))
506 Warning(("cQuestData::Load - bad save format\n"));
507 return E_FAIL;
509 if ((num = moveFunc((void*)&value, sizeof(int), 1)) != sizeof(int))
511 Warning(("cQuestData::Load - bad save format\n"));
512 return E_FAIL;
514 Create(pName, value, type);
516 return S_OK;
519 void cQuestData::ObjListener(ObjID objID, eObjNotifyMsg msg, void *data)
521 AutoAppIPtr(QuestData);
522 if (msg == kObjNotifyDelete)
523 pQuestData->ObjDeleteListener(objID);
526 STDMETHODIMP cQuestData::ObjDeleteListener(ObjID objID)
528 cQuestNodeList *pSubscribedList;
529 if (m_subscriberHash.Lookup(objID, &pSubscribedList))
531 cQuestNodeList::cIter iter = pSubscribedList->Iter();
533 for (; !iter.Done(); iter.Next())
535 cQuestDataNode* pNode = iter.Value();
536 pNode->m_subscriberList.RemoveElem(objID);
539 delete pSubscribedList;
540 m_subscriberHash.Delete(objID);
542 return S_OK;
545 #ifndef SHIP
546 STDMETHODIMP cQuestData::ObjSpewListen(ObjID objID)
548 cQuestNodeList *pSubscribedList;
549 if (m_subscriberHash.Lookup(objID, &pSubscribedList))
551 cQuestNodeList::cIter iter = pSubscribedList->Iter();
552 for (; !iter.Done(); iter.Next())
554 cQuestDataNode* pQuestNode = iter.Value();
555 mprintf("%s ", pQuestNode->m_pName);
558 return S_OK;
560 #endif
562 // @NOTE: the implementation currently only allows for a single filter.
563 // We could enhance this to allow any number of filters, but do bear in
564 // mind that they will all be run on every Set(), so this can get
565 // expensive...
566 STDMETHODIMP cQuestData::Filter(QuestFilterFunc filter, void *pClientData)
568 m_filter = filter;
569 m_pClientData = pClientData;
570 return S_OK;
573 void QuestDataCreate()
575 AutoAppIPtr(Unknown);
576 new cQuestData(pUnknown);