2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
6 // $Header: r:/t2repos/thief2/src/engfeat/quest.cpp,v 1.14 1999/08/31 17:42:29 Justin Exp $
41 // Include these absolutely last
46 //------------------------------------------------------------
50 class cObjList
: public cSimpleListSet
<ObjID
>
54 // List for storing pointers to data nodes for each object that subscribes to data change messages
57 typedef cSimpleDList
<cQuestDataNode
*> cQuestNodeList
;
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
;
89 //------------------------------------------------------------
90 // Forward declare the iterator class
92 class cQuestDataIter
: public cCTUnaggregated
<IQuestDataIter
,&IID_IQuestDataIter
,kCTU_Default
>
95 tHashSetHandle m_handle
;
96 cQuestDataNode
*m_pNode
;
97 const cQuestDataHash
*m_pHash
;
98 eQuestDataType m_type
;
102 while ((m_pNode
!= NULL
) && (m_pNode
->m_type
!= m_type
))
104 m_pNode
= m_pHash
->GetNext(m_handle
);
110 cQuestDataIter(const cQuestDataHash
*pHash
, eQuestDataType type
):
111 m_pNode(pHash
->GetFirst(m_handle
)),
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
[];
136 cQuestData(IUnknown
* pOuter
)
139 MI_INIT_AGGREGATION_1(pOuter
, IQuestData
, kPriorityNormal
, gConstraints
);
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);
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
)();
190 STDMETHOD(ObjSpewListen
)(ObjID objID
);
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
);
201 tObjListenerHandle m_listenerHandle
;
202 cQuestDataHash m_nameHash
;
203 cQuestSubscribeHash m_subscriberHash
;
204 QuestFilterFunc m_filter
;
208 static sNetMsgDesc gm_CreateMsgDesc
;
209 cNetMsg
*m_pCreateMsg
;
210 static sNetMsgDesc gm_SetMsgDesc
;
216 // Network dispatching stuff
219 static void dispatchCreate(const char *pName
,
224 ((cQuestData
*) pQuestData
)->doCreate(pName
, value
, type
);
227 sNetMsgDesc
cQuestData::gm_CreateMsgDesc
= {
239 static void dispatchSet(const char *pName
,
243 ((cQuestData
*) pQuestData
)->doSet(pName
, value
);
246 sNetMsgDesc
cQuestData::gm_SetMsgDesc
= {
258 sRelativeConstraint
cQuestData::gConstraints
[] =
260 { kConstrainAfter
, &IID_IObjectSystem
},
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
);
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
;
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
;
302 pNode
= new cQuestDataNode(pName
, type
);
303 pNode
->m_value
= value
;
304 m_nameHash
.Insert(pNode
);
307 pNode
->SendMsgs(oldValue
);
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
;
327 if (!m_filter(pName
, oldValue
, value
))
331 pNode
->m_value
= value
;
332 pNode
->SendMsgs(oldValue
);
336 STDMETHODIMP_(BOOL
) cQuestData::Get(const char *pName
)
338 cQuestDataNode
*pNode
;
340 if ((pNode
= m_nameHash
.Search(pName
)) != NULL
)
341 return pNode
->m_value
;
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
);
372 STDMETHODIMP
cQuestData::UnsubscribeMsg(ObjID objID
, const char *pName
)
374 cQuestDataNode
* pQuestNode
= m_nameHash
.Search(pName
);
375 if (pQuestNode
== NULL
)
378 // remove from subscriber list
379 if (!pQuestNode
->m_subscriberList
.RemoveElem(objID
))
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());
399 // if the list is now empty... get rid of it
400 if (pSubscribedList
->GetFirst() == NULL
)
402 m_subscriberHash
.Delete(objID
);
403 delete pSubscribedList
;
409 STDMETHODIMP
cQuestData::UnsubscribeAll()
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();
425 m_subscriberHash
.Clear();
431 STDMETHODIMP
cQuestData::Delete(THIS_
const char *pName
)
433 cQuestDataNode
*pNode
= m_nameHash
.Search(pName
);
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
);
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
);
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
);
471 STDMETHODIMP_(BOOL
) cQuestData::Save(QuestMoveFunc moveFunc
, eQuestDataType type
)
473 tHashSetHandle handle
;
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
);
492 STDMETHODIMP_(BOOL
) cQuestData::Load(QuestMoveFunc moveFunc
, eQuestDataType type
)
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
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"));
509 if ((num
= moveFunc((void*)&value
, sizeof(int), 1)) != sizeof(int))
511 Warning(("cQuestData::Load - bad save format\n"));
514 Create(pName
, value
, type
);
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
);
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
);
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
566 STDMETHODIMP
cQuestData::Filter(QuestFilterFunc filter
, void *pClientData
)
569 m_pClientData
= pClientData
;
573 void QuestDataCreate()
575 AutoAppIPtr(Unknown
);
576 new cQuestData(pUnknown
);