convert line ends
[canaan.git] / prj / cam / src / script / sndscrpt.cpp
blob27306579924525568231c859ab5e3f28188a3a99
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 ///////////////////////////////////////////////////////////////////////////////
7 // $Header: r:/t2repos/thief2/src/script/sndscrpt.cpp,v 1.36 1999/08/05 17:34:28 Justin Exp $
8 //
9 // sndscrpt.cpp
11 #include <lg.h>
12 #include <mprintf.h>
13 #include <appagg.h>
14 #include <lazyagg.h>
16 #include <iobjsys.h>
17 #include <scrptapi.h>
18 #include <scrptbas.h>
19 #include <scrptsrv.h>
21 #include <appsfx.h>
22 #include <objpos.h>
23 #include <osystype.h>
24 #include <psnd.h>
25 #include <schbase.h>
26 #include <schema.h>
27 #include <config.h>
28 #include <cfgdbg.h>
29 #include <esnd.h>
30 #include <ctagset.h>
31 #include <string.h>
32 #include <objedit.h>
33 #include <objremap.h>
34 #include <speech.h>
36 #include <sndscrpt.h>
37 #include <sndscrp_.h>
38 #include <vocore.h>
40 #include <tagfile.h>
41 #include <vernum.h>
43 // Include this last, please
44 #include <dbmem.h>
46 // Our special spew that works in playtest
47 #ifdef PLAYTEST
48 #define sndSpew(x) if (!config_is_defined("ScriptSoundSpew")) ; else mprintf x
49 #else
50 #define sndSpew(x)
51 #endif
53 ///////////////////////////////////////////////////////////////////////////////
55 // Message implementations
58 // We keep track of all sounds started by scripts, and when they end
59 // we use our callback to run the SoundDone or SchemaDone message on
60 // whichever object's script started the sound.
62 enum eSndPlayType
64 kPlayNone,
65 kPlaySound,
66 kPlaySchema,
67 kPlaySchemaEnv,
70 #define MAX_TAG_SIZE 128
72 // The handles used by the schema system come directly from appsfx.
73 // So we can depend on them to be unique no matter what calls they
74 // come from.
75 class cSoundRecord
77 public:
78 int m_iHandle;
79 mxs_vector m_Coordinates;
80 ObjID m_CallbackObjID;
81 ObjID m_TargetObjID; // the sound was played _on_ this object
82 Label m_Name; // either the sound name or the schema name
83 BOOL m_bIsSchema;
85 // horrifying replay system
86 eSndPlayType m_replay;
87 eEnvSoundLoc m_eLoc;
88 int m_iFlags;
89 BOOL m_bAmbient;
90 ObjID m_Obj2;
91 char m_envTagsString[MAX_TAG_SIZE];
93 cSoundRecord(int iHandle,
94 mxs_vector *pCoordinates,
95 ObjID CallbackObjID,
96 ObjID TargetObjID,
97 Label *Name,
98 BOOL bIsSchema)
99 : m_iHandle(iHandle),
100 m_Coordinates(*pCoordinates),
101 m_CallbackObjID(CallbackObjID),
102 m_TargetObjID(TargetObjID),
103 m_Name(*Name),
104 m_bIsSchema(bIsSchema)
108 cSoundRecord()
113 static BOOL kill_on_load=FALSE;
115 // This is used to keep track of both active raw sounds and active
116 // schemas.
117 static cDynArray<cSoundRecord *> g_ActiveSounds;
119 static LazyAggMember(IObjectSystem) pObjSys;
120 static LazyAggMember(IScriptMan) pScriptMan;
122 ///////////////////////
123 // init/term
125 void ScriptSoundInit(void)
127 if (config_is_defined("sndscrpt_kill_restart"))
128 kill_on_load=TRUE;
131 void ScriptSoundTerm(void)
135 ///////////////////////
136 // handle generators
138 // these are later in the file, sorry
139 static void ActiveSchemaDoneCallback(int iHandle, int iSchemaID, void *pIgnoreUserData);
140 static void SFXParamsSetup(sfx_parm *pParams, int iFlags, eSoundNetwork net);
142 static void SchemaParamsSetup(sSchemaCallParams *pParams,
143 ObjID SourceObjID,
144 mxs_vector *Coordinates,
145 ulong iFlags,
146 eSoundNetwork net)
148 pParams->flags = SCH_SET_CALLBACK | SCH_FORCE_PLAY | iFlags;
149 if (net == kSoundNetworkAmbient)
150 pParams->flags |= SCH_NETWORK;
151 else if (net == kSoundNoNetworkSpatial)
152 pParams->flags |= SCH_NO_NETWORK;
153 pParams->sourceID = SourceObjID;
154 pParams->callback = ActiveSchemaDoneCallback;
155 pParams->pSourceLoc = Coordinates;
158 static int SndScrptGen(Label *lname, int iFlags, ObjID call, ObjID targ, ObjID obj2,
159 mxs_vector *crd, cTagSet *pTags, BOOL amb, eEnvSoundLoc loc, eSndPlayType play, eSoundNetwork net)
161 sSchemaCallParams CallParams;
162 int iHandle=SFX_NO_HND;
163 switch (play)
165 case kPlayNone:
166 break;
167 case kPlaySound:
168 sfx_parm parm;
169 SFXParamsSetup(&parm, iFlags, net);
170 if (amb)
171 iHandle = g_pPropSnd->GenerateSound(lname->text, &parm);
172 else
173 iHandle = g_pPropSnd->GenerateSound(targ, OBJ_NULL, lname->text, 1.0, &parm, kGSF_ForcePlay);
174 break;
175 case kPlaySchema:
176 SchemaParamsSetup(&CallParams, targ, crd, iFlags, net);
177 iHandle = SchemaPlay(lname, &CallParams);
178 break;
179 case kPlaySchemaEnv:
180 SchemaParamsSetup(&CallParams, targ, crd, iFlags, net);
181 switch (loc)
183 case kEnvSoundOnObj:
184 iHandle = ESndPlayObj(pTags, targ, obj2, &CallParams);
185 break;
186 case kEnvSoundAtObjLoc:
187 iHandle = ESndPlayLoc(pTags, targ, obj2, crd, &CallParams);
188 break;
189 case kEnvSoundAmbient:
190 iHandle = ESndPlay(pTags, targ, obj2, &CallParams);
191 break;
193 break;
195 return iHandle;
198 ///////////////////////
199 // save/load
201 #define kSndScriptSaveVer 1
202 static TagFileTag sound_tag = {"SndScript"};
203 static TagVersion sound_ver = { kSndScriptSaveVer, 0 };
205 void ScriptSoundSave(ITagFile *file)
206 { // go through and write out the data we need
207 HRESULT result=file->OpenBlock(&sound_tag,&sound_ver);
208 BOOL failed=FALSE;
209 if (result!=S_OK)
210 return;
211 int cnt=g_ActiveSounds.Size();
212 file->Write((char *)&cnt,sizeof(int));
213 for (int i = 0; i < g_ActiveSounds.Size(); ++i)
214 if (file->Write((char *)g_ActiveSounds[i],sizeof(cSoundRecord))!=sizeof(cSoundRecord))
216 failed=TRUE;
217 Warning(("ActiveSounds failed to write\n"));
218 break;
220 sndSpew(("sndscrpt Saved %d records\n",cnt));
221 file->CloseBlock();
224 BOOL SndScriptRestartSavedSounds(cSoundRecord *sndDat)
226 BOOL worked=FALSE;
227 cTagSet tmp; // here comes the HACK HACK HACK
229 sndDat->m_CallbackObjID = ObjRemapOnLoad(sndDat->m_CallbackObjID);
230 sndDat->m_TargetObjID = ObjRemapOnLoad(sndDat->m_TargetObjID);
231 if (sndDat->m_replay==kPlaySchemaEnv)
232 { // only used for schemaEnv, so really
233 tmp.FromString(sndDat->m_envTagsString);
234 sndDat->m_Obj2 = ObjRemapOnLoad(sndDat->m_Obj2);
237 int hnd =
238 SndScrptGen(&sndDat->m_Name,sndDat->m_iFlags,
239 sndDat->m_CallbackObjID,sndDat->m_TargetObjID,sndDat->m_Obj2,
240 &sndDat->m_Coordinates,&tmp,sndDat->m_bAmbient,sndDat->m_eLoc,
241 sndDat->m_replay,kSoundNetDefault);
242 if (sndDat->m_replay==kPlaySound)
243 worked=(hnd!=SFX_NO_HND);
244 else
245 worked=(hnd!=SCH_HANDLE_NULL);
246 if (worked)
248 sndDat->m_iHandle=hnd;
249 g_ActiveSounds.Append(sndDat);
250 sndSpew(("Restarted %s (callback %s targ %s) type %d\n",sndDat->m_Name.text,
251 ObjWarnName(sndDat->m_CallbackObjID),
252 ObjWarnName(sndDat->m_TargetObjID),
253 sndDat->m_replay));
255 return worked;
258 void SndScriptSendSavedMsg(cSoundRecord *sndDat)
260 // need to ObjRemap here, i think....
261 sndDat->m_CallbackObjID = ObjRemapOnLoad(sndDat->m_CallbackObjID);
262 sndDat->m_TargetObjID = ObjRemapOnLoad(sndDat->m_TargetObjID);
263 sndSpew(("savedispatch call %s targ %s - %s (a %s)\n",
264 ObjWarnName(sndDat->m_CallbackObjID),
265 ObjWarnName(sndDat->m_TargetObjID),
266 sndDat->m_Name.text,
267 sndDat->m_bIsSchema?"Schema":"Sound"
269 if (sndDat->m_bIsSchema)
271 sSchemaDoneMsg *pMsg
272 = new sSchemaDoneMsg(sndDat->m_CallbackObjID,
273 sndDat->m_TargetObjID,
274 sndDat->m_Coordinates,
275 sndDat->m_Name.text);
276 pScriptMan->PostMessage(pMsg);
277 SafeRelease(pMsg);
279 else
281 sSoundDoneMsg *pMsg
282 = new sSoundDoneMsg(sndDat->m_CallbackObjID,
283 sndDat->m_TargetObjID,
284 sndDat->m_Coordinates,
285 sndDat->m_Name.text);
286 pScriptMan->PostMessage(pMsg);
287 SafeRelease(pMsg);
291 static cDynArray<cSoundRecord *> _LoadSounds;
293 void ScriptSoundLoad(ITagFile *file)
294 { // go through and postmessage the kills
295 TagVersion local_ver=sound_ver;
296 HRESULT result=file->OpenBlock(&sound_tag,&local_ver);
297 BOOL failed=FALSE;
298 int cnt=-1;
300 if (result==S_OK)
302 if (file->Read((char *)&cnt,sizeof(int))==sizeof(int))
303 for (int i = 0; i < cnt; ++i)
305 cSoundRecord *tmpSoundRec = new cSoundRecord();
306 if (file->Read((char *)tmpSoundRec,sizeof(cSoundRecord))!=sizeof(cSoundRecord))
308 failed=TRUE;
309 Warning(("ActiveSounds failed to read\n"));
310 delete tmpSoundRec;
311 break;
313 else
314 _LoadSounds.Append(tmpSoundRec);
316 else
317 Warning(("ActiveSounds couldnt get a count\n"));
318 file->CloseBlock();
320 sndSpew(("sndscrpt loaded %d records\n",cnt));
323 void ScriptSoundPostLoad(void)
325 for (int i=0; i<_LoadSounds.Size(); i++)
327 if (kill_on_load)
329 SndScriptSendSavedMsg(_LoadSounds[i]);
330 delete _LoadSounds[i];
332 else
334 if (!SndScriptRestartSavedSounds(_LoadSounds[i]))
336 SndScriptSendSavedMsg(_LoadSounds[i]);
337 delete _LoadSounds[i];
341 _LoadSounds.SetSize(0);
344 // if the data is real, call postload
345 void ScriptSoundEnterModeHack(void)
347 ScriptSoundPostLoad();
350 void ScriptSoundReset(void)
352 if (g_ActiveSounds.Size())
354 #ifndef SHIP
355 mprintf("Reseting Script Sounds but there are active sounds - TELL DOUG\n");
356 #endif
360 ///////////////////////
361 // callbacks
363 // When a scripted schema finishes, we do this.
364 static void ActiveSchemaDoneCallback(int iHandle, int iSchemaID,
365 void *pIgnoreUserData)
367 if (g_ActiveSounds.Size() == 0)
368 Warning(("No scripted schemas playing in callback; handle is %d\n",
369 iHandle));
371 sndSpew(("Schema %s is done (handle %d)\n", ObjWarnName(iSchemaID), iHandle));
373 for (int i = 0; i < g_ActiveSounds.Size(); ++i) {
374 if (g_ActiveSounds[i]->m_iHandle == iHandle) {
375 #ifdef PLAYTEST
376 if (g_ActiveSounds[i]->m_bIsSchema == FALSE)
377 Warning(("Scripted schema callback found raw schema %d."
378 " Yeah, Whatever.\n", g_ActiveSounds[i]->m_iHandle));
379 #endif // ~PLAYTEST
381 sndSpew((" found!\n"));
383 sSchemaDoneMsg *pMsg
384 = new sSchemaDoneMsg(g_ActiveSounds[i]->m_CallbackObjID,
385 g_ActiveSounds[i]->m_TargetObjID,
386 g_ActiveSounds[i]->m_Coordinates,
387 g_ActiveSounds[i]->m_Name.text);
388 pScriptMan->PostMessage(pMsg);
389 SafeRelease(pMsg);
391 delete g_ActiveSounds[i];
392 g_ActiveSounds.DeleteItem(i);
394 return;
398 sndSpew((" not found!\n"));
399 #ifdef PLAYTEST
400 for (int k=0; k<g_ActiveSounds.Size(); k++)
401 sndSpew((" %s, handle %d\n", ObjWarnName(g_ActiveSounds[k]->m_TargetObjID), g_ActiveSounds[k]->m_iHandle));
402 #endif
404 Warning(("Scripted schema handle not found in callback: %d\n", iHandle));
408 static void ActiveSoundDoneCallback(int iHandle, void *pIgnoreUserData)
410 if (g_ActiveSounds.Size() == 0)
411 Warning(("No scripted sounds playing in callback; handle is %d\n",
412 iHandle));
414 for (int i = 0; i < g_ActiveSounds.Size(); ++i) {
415 if (g_ActiveSounds[i]->m_iHandle == iHandle) {
416 #ifdef PLAYTEST
417 if (g_ActiveSounds[i]->m_bIsSchema == TRUE)
418 Warning(("Scripted raw sound callback found schema %d."
419 " Yeah, Whatever.\n", g_ActiveSounds[i]->m_iHandle));
420 #endif // ~PLAYTEST
422 sSoundDoneMsg *pMsg
423 = new sSoundDoneMsg(g_ActiveSounds[i]->m_CallbackObjID,
424 g_ActiveSounds[i]->m_TargetObjID,
425 g_ActiveSounds[i]->m_Coordinates,
426 g_ActiveSounds[i]->m_Name.text);
427 pScriptMan->PostMessage(pMsg);
428 SafeRelease(pMsg);
430 delete g_ActiveSounds[i];
431 g_ActiveSounds.DeleteItem(i);
433 return;
437 Warning(("Scripted sound handle not found in callback: %d\n", iHandle));
441 // This is a lobotomized version of SchemaParamsSetup in schema.cpp.
442 // When we go back and add support for panning, custom fades, etc., we
443 // can pattern it after that.
444 static void SFXParamsSetup(sfx_parm *pParams, int iFlags, eSoundNetwork net)
446 pParams->flag = iFlags;
447 if (net == kSoundNetworkAmbient)
448 pParams->flag |= SFXFLG_NET_AMB;
449 else if (net == kSoundNoNetworkSpatial)
450 pParams->flag |= SFXFLG_NO_NET;
451 pParams->group = 0;
452 pParams->end_callback = &ActiveSoundDoneCallback;
453 pParams->loop_callback = NULL;
454 pParams->user_data = 0;
455 pParams->radius = 0;
456 pParams->pan = 0;
457 pParams->gain = -1;
458 pParams->delay = 0;
459 pParams->fade = 0;
460 pParams->pri = 0;
461 pParams->num_loops = SFX_LOOP_INFINITE;
465 // This is the stuff held in common by the three sound playing
466 // routines.
467 static bool PlayAndRememberSound(const char *SoundName,
468 ObjID CallObjID,
469 ObjID TargObjID,
470 mxs_vector *pCoord,
471 BOOL bAmbient,
472 eSoundSpecial Special = kSoundNormal,
473 eSoundNetwork Network = kSoundNetDefault)
475 Label SoundLabel;
476 memcpy(&SoundLabel.text, SoundName, 15);
477 SoundLabel.text[15] = 0;
479 // start our sound
480 int iFlags;
481 switch (Special)
483 case kSoundLoop:
484 iFlags = SFXFLG_LOOP;
485 break;
486 default:
487 iFlags = 0;
488 break;
490 int iHandle = SndScrptGen(&SoundLabel,iFlags,CallObjID,TargObjID,OBJ_NULL,
491 pCoord,NULL,bAmbient,(eEnvSoundLoc)0,kPlaySound,
492 Network);
494 if (iHandle != SFX_NO_HND)
496 cSoundRecord *t = new cSoundRecord(iHandle, pCoord, CallObjID, TargObjID, &SoundLabel, FALSE);
498 // @REPLAY - needs iFlags, bAmibent
499 t->m_bAmbient = bAmbient;
500 t->m_iFlags = iFlags;
501 t->m_replay = kPlaySound;
503 sndSpew(("Script on %s added sound %s\n", ObjWarnName(CallObjID), SoundName));
505 #ifdef PLAYTEST
506 for (int k = 0; k < g_ActiveSounds.Size(); k++)
507 Assert_(g_ActiveSounds[k]->m_iHandle != iHandle);
508 #endif
510 g_ActiveSounds.Append(t);
511 return TRUE;
512 } else {
513 sndSpew(("Script on %s failed to play sound %s\n", ObjWarnName(CallObjID), SoundName));
514 return FALSE;
519 static bool PlayAndRememberSchema(ObjID SchemaID,
520 ObjID CallObjID,
521 ObjID TargObjID,
522 mxs_vector *pCoord,
523 ulong iFlags,
524 eSoundNetwork Network)
526 if (!SchemaID) {
527 #ifdef PLAYTEST
528 mprintf("Script on %s requested nonexistent schema!\n",ObjWarnName(CallObjID));
529 #endif
530 return FALSE;
533 const char* name = pObjSys->GetName(SchemaID);
535 Label SchemaLabel;
536 strncpy(SchemaLabel.text,name,sizeof(Label));
537 SchemaLabel.text[sizeof(Label)-1] = '\0';
539 int iHandle = SndScrptGen(&SchemaLabel,iFlags,CallObjID,TargObjID,OBJ_NULL,
540 pCoord,NULL,0,(eEnvSoundLoc)0,kPlaySchema,
541 Network);
543 if (iHandle != SCH_HANDLE_NULL)
545 cSoundRecord *t = new cSoundRecord(iHandle, pCoord, CallObjID, TargObjID, &SchemaLabel, TRUE);
547 // @REPLAY - iFlags
548 t->m_iFlags = iFlags;
549 t->m_replay = kPlaySchema;
551 sndSpew(("Script on %s adding schema %s\n",
552 ObjWarnName(CallObjID), SchemaLabel.text));
553 #ifdef PLAYTEST
554 for (int k = 0; k < g_ActiveSounds.Size(); k++)
555 Assert_(g_ActiveSounds[k]->m_iHandle != iHandle);
556 #endif
558 g_ActiveSounds.Append(t);
559 return TRUE;
560 } else {
561 sndSpew(("Script on %s failed to play schema %s\n",
562 ObjWarnName(CallObjID), SchemaLabel.text));
563 return FALSE;
569 static bool PlayAndRememberEnvSchema(ObjID CallObjID,
570 ObjID SrcObjID,
571 ObjID Obj2,
572 cTagSet *pTagSet,
573 mxs_vector *pCoord,
574 ulong iFlags,
575 eEnvSoundLoc loc = kEnvSoundAmbient,
576 eSoundNetwork Network = kSoundNetDefault)
578 int iHandle = SndScrptGen(NULL,iFlags,CallObjID,SrcObjID,Obj2,pCoord,pTagSet,FALSE,loc,kPlaySchemaEnv,Network);
580 if (iHandle != SCH_HANDLE_NULL)
582 const char* name = pObjSys->GetName(SchemaGetIDFromHandle(iHandle));
583 Label label;
584 strncpy(label.text,name,sizeof(label.text));
585 label.text[sizeof(label.text)-1] = '\0';
587 cSoundRecord *t = new cSoundRecord(iHandle,pCoord,CallObjID,SrcObjID,&label,TRUE);
589 // @REPLAY - iFlags, loc, Obj2, tags
590 t->m_iFlags = iFlags;
591 t->m_eLoc = loc;
592 t->m_replay = kPlaySchemaEnv;
593 t->m_Obj2 = Obj2;
594 cStr tmp;
595 pTagSet->ToString(&tmp);
596 strncpy(t->m_envTagsString,(const char *)tmp,MAX_TAG_SIZE);
598 #ifdef PLAYTEST
599 for (int k = 0; k < g_ActiveSounds.Size(); k++)
600 Assert_(g_ActiveSounds[k]->m_iHandle != iHandle);
601 #endif
603 g_ActiveSounds.Append(t);
604 sndSpew(("Script on %s Obj %s Handle %d\n",label.text,ObjWarnName(SrcObjID),iHandle));
605 return TRUE;
607 else
609 #ifdef PLAYTEST
610 if (pTagSet && pTagSet->Size())
612 cStr tmpStr;
613 pTagSet->ToString(&tmpStr);
614 sndSpew(("Script on %s failed to play env schema (tags %s)\n", ObjWarnName(CallObjID), tmpStr));
616 else
617 sndSpew(("Script on %s failed to play env schema\n", ObjWarnName(CallObjID)));
618 #endif
619 return FALSE;
624 // We can halt all sounds on a given object, or get more specific,
625 // requiring a given sound or schema name and even a callback object.
626 static int HaltActiveSounds(ObjID TargetObjID,
627 const char *pszName,
628 ObjID CallbackObjID,
629 BOOL bIsSchema)
631 cSoundRecord *pRecord;
632 int iNumHalted = 0;
633 BOOL bAnyName = FALSE;
634 BOOL bAnyCallbackObjID = FALSE;
636 #ifdef PLAYTEST
637 if (strlen(pszName) > 15)
638 mprintf("WARNING: HaltActiveSounds: %s longer than 15 characters.\n", pszName);
639 #endif // PLAYTEST
641 if (*pszName == 0)
642 bAnyName = TRUE;
644 if (CallbackObjID == OBJ_NULL)
645 bAnyCallbackObjID = TRUE;
647 // Copy the array as halts will mutate the global array
648 cDynArray<cSoundRecord *> activeSounds(g_ActiveSounds);
650 #ifdef PLAYTEST
651 sndSpew(("Script going to halt for %s\n", ObjWarnName(TargetObjID)));
652 sndSpew(("Soundlist (size %d)\n", activeSounds.Size()));
653 for (int k=0; k<activeSounds.Size(); k++)
654 sndSpew((" on %s, handle %d\n", ObjWarnName(activeSounds[k]->m_TargetObjID), activeSounds[k]->m_iHandle));
655 #endif
657 for (int i = 0; i < activeSounds.Size(); ++i) {
658 pRecord = activeSounds[i];
660 if ((pRecord->m_bIsSchema == bIsSchema) &&
661 (pRecord->m_TargetObjID == TargetObjID) &&
662 (bAnyName || (strcmp(pszName, pRecord->m_Name.text) == 0)) &&
663 (bAnyCallbackObjID || (pRecord->m_CallbackObjID == CallbackObjID)))
665 sndSpew(("Script Halting %s%s for obj %s (cback obj %s) handle %d\n",
666 pszName[0]=='\0'?"Unknown":pszName,
667 bIsSchema?" (a Schema)":" (a Sound)",
668 ObjWarnName(TargetObjID),ObjWarnName(CallbackObjID),pRecord->m_iHandle));
670 if (bIsSchema)
671 SchemaPlayHalt(pRecord->m_iHandle);
672 else
673 g_pPropSnd->SoundHalt(pRecord->m_iHandle);
675 ++iNumHalted;
679 return iNumHalted;
683 IMPLEMENT_SCRMSG_PERSISTENT(sSoundDoneMsg)
685 PersistenceHeader(sScrMsg, kSoundDoneMsgVer);
686 Persistent(coordinates);
687 Persistent(targetObject);
688 Persistent(name);
690 return TRUE;
694 IMPLEMENT_SCRMSG_PERSISTENT(sSchemaDoneMsg)
696 PersistenceHeader(sScrMsg, kSchemaDoneMsgVer);
697 Persistent(coordinates);
698 Persistent(targetObject);
699 Persistent(name);
701 return TRUE;
704 ///////////////////////////////////////////////////////////////////////////////
706 // CLASS: cDebugScrSrv
710 DECLARE_SCRIPT_SERVICE_IMPL(cSoundScrSrv, Sound)
712 public:
714 ////////////////////////////////////
716 // four routines for playing sounds...
719 // If we do not have a target object or set of coordinates, we
720 // assume our sound is coming from the object playing the script.
721 STDMETHOD_ (boolean, Play)(object CallbackObjID,
722 const string ref SoundName,
723 eSoundSpecial Special = kSoundNormal,
724 eSoundNetwork Network = kSoundNetDefault)
727 ObjID ScriptID = ScriptObjID(CallbackObjID);
728 Position *Pos = ObjPosGet(ScriptID);
729 mxs_vector Coordinates;
731 if (Pos == 0)
732 mx_zero_vec(&Coordinates);
733 else
734 Coordinates = Pos->loc.vec;
736 return PlayAndRememberSound(SoundName, ScriptID, ScriptID,
737 &Coordinates, FALSE, Special, Network);
740 // We'll record the coordinates of the target object. Naturally,
741 // this doesn't keep it from moving before the sound finishes.
742 STDMETHOD_ (boolean, Play)(object CallbackObjID,
743 const string ref SoundName,
744 object TargetObj,
745 eSoundSpecial Special = kSoundNormal,
746 eSoundNetwork Network = kSoundNetDefault)
748 ObjID ScriptID = ScriptObjID(CallbackObjID);
749 ObjID TargetID = ScriptObjID(TargetObj);
750 Position *Pos = ObjPosGet(TargetID);
751 mxs_vector Coordinates;
753 if (Pos == 0)
754 mx_zero_vec(&Coordinates);
755 else
756 Coordinates = Pos->loc.vec;
758 return PlayAndRememberSound(SoundName, ScriptID, TargetID,
759 &Coordinates, FALSE, Special, Network);
762 // We set the target object to OBJ_NULL if we're playing to
763 // coordinates.
764 STDMETHOD_ (boolean, Play)(object CallbackObjID,
765 const string ref SoundName,
766 vector ref Location,
767 eSoundSpecial Special = kSoundNormal,
768 eSoundNetwork Network = kSoundNetDefault)
770 ObjID ScriptID = ScriptObjID(CallbackObjID);
771 return PlayAndRememberSound(SoundName, ScriptID, OBJ_NULL,
772 &Location, FALSE, Special, Network);
775 STDMETHOD_ (boolean, PlayAmbient)(object CallbackObjID,
776 const string ref SoundName,
777 eSoundSpecial Special = kSoundNormal,
778 eSoundNetwork Network = kSoundNetDefault)
780 ObjID ScriptID = ScriptObjID(CallbackObjID);
781 mxs_vector Coordinates;
782 mx_zero_vec(&Coordinates);
784 return PlayAndRememberSound(SoundName, ScriptID, ScriptID,
785 &Coordinates, TRUE, Special, Network);
788 ////////////////////////////////////
790 // four routines for playing schemas
792 STDMETHOD_ (boolean, PlaySchema)(object CallbackObjID,
793 object Schema,
794 eSoundNetwork Network = kSoundNetDefault)
796 ObjID ScriptID = ScriptObjID(CallbackObjID);
797 Position *Pos = ObjPosGet(ScriptID);
798 mxs_vector Coordinates;
800 if (Pos == 0)
801 mx_zero_vec(&Coordinates);
802 else
803 Coordinates = Pos->loc.vec;
805 return PlayAndRememberSchema(Schema, ScriptID, ScriptID,
806 &Coordinates, SCH_SET_OBJ, Network);
809 STDMETHOD_ (boolean, PlaySchema)(object CallbackObjID,
810 object Schema,
811 object TargetObj,
812 eSoundNetwork Network = kSoundNetDefault)
814 ObjID ScriptID = ScriptObjID(CallbackObjID);
815 ObjID TargetID = ScriptObjID(TargetObj);
816 Position *Pos = ObjPosGet(TargetID);
817 mxs_vector Coordinates;
819 if (Pos == 0)
820 mx_zero_vec(&Coordinates);
821 else
822 Coordinates = Pos->loc.vec;
824 return PlayAndRememberSchema(Schema, ScriptID, TargetID,
825 &Coordinates, SCH_SET_OBJ, Network);
828 STDMETHOD_ (boolean, PlaySchema)(object CallbackObjID,
829 object Schema,
830 vector ref Location,
831 eSoundNetwork Network = kSoundNetDefault)
833 ObjID ScriptID = ScriptObjID(CallbackObjID);
834 return PlayAndRememberSchema(Schema, ScriptID, OBJ_NULL,
835 &Location, SCH_SET_LOC, Network);
838 STDMETHOD_ (boolean, PlaySchemaAmbient)(object CallbackObjID,
839 object Schema,
840 eSoundNetwork Network = kSoundNetDefault)
842 ObjID ScriptID = ScriptObjID(CallbackObjID);
843 mxs_vector Coordinates;
844 mx_zero_vec(&Coordinates);
846 return PlayAndRememberSchema(Schema, ScriptID, ScriptID,
847 &Coordinates, 0, Network);
851 STDMETHOD_(boolean, PlayEnvSchema)(object CallbackObject,
852 const string ref Tags,
853 object SourceObject, object Agent,
854 eEnvSoundLoc loc = kEnvSoundAmbient,
855 eSoundNetwork Network = kSoundNetDefault)
857 cTagSet TagSet(Tags);
859 ObjID ScriptID = ScriptObjID(CallbackObject);
860 ObjID SourceID = ScriptObjID(SourceObject);
861 if (SourceID == OBJ_NULL)
862 SourceID = ScriptID;
863 Position *Pos = ObjPosGet(SourceID);
864 mxs_vector Coordinates;
866 if (Pos)
867 Coordinates = Pos->loc.vec;
868 else
869 mx_zero_vec(&Coordinates);
871 ulong flags = (loc == kEnvSoundOnObj) ? SCH_SET_OBJ : 0;
873 return PlayAndRememberEnvSchema(ScriptID,
874 SourceID,
875 Agent,
876 &TagSet,
877 &Coordinates,
878 flags,
879 loc,
880 Network);
885 STDMETHOD_(boolean, PlayVoiceOver)(object cb_obj, object schema)
887 AutoAppIPtr(VoiceOverSys);
889 int iHandle = pVoiceOverSys->Play(schema);
891 if (iHandle != SCH_HANDLE_NULL)
892 return TRUE;
893 else
895 ConfigSpew("ScriptSoundSpew",("Script on object %d failed to play schema %d"));
897 return FALSE;
902 ////////////////////////////////////
904 // two routines to undo the stuff the other ones do
907 STDMETHOD_(integer, Halt)(object TargetObject,
908 const string ref SoundName,
909 object CallbackObject)
911 return HaltActiveSounds(TargetObject, SoundName, CallbackObject, FALSE);
914 STDMETHOD_(boolean, HaltSchema)(object TargetObject,
915 const string ref SchemaName,
916 object CallbackObject)
918 return HaltActiveSounds(TargetObject, SchemaName, CallbackObject, TRUE);
922 STDMETHOD(HaltSpeech)(object speakerObj)
924 SpeechHalt(speakerObj);
925 return S_OK;
928 STDMETHOD_(boolean,PreLoad)(const string ref SpeechName)
930 return SFX_PreLoad(SpeechName);
934 IMPLEMENT_SCRIPT_SERVICE_IMPL(cSoundScrSrv, Sound);
936 ///////////////////////////////////////////////////////////////////////////////