EVENTQ.CPP 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. #include <stdlib.h>
  2. #include "engine.h"
  3. #include "debug4g.h"
  4. #include "error.h"
  5. #include "eventq.h"
  6. #include "db.h"
  7. #include "pqueue.h"
  8. #include "triggers.h"
  9. #include "globals.h"
  10. #include "levels.h"
  11. #define kMaxChannels 4096
  12. #define kMaxID 1024
  13. static PriorityQueue eventQ;
  14. /*******************************************************************************
  15. Each channel bucket is a contiguous range in a rxBucket[] array. The
  16. bucketHead[] array points to the start index for each channel id. Creating the
  17. buckets is not particularly fast, but using them is very fast and storage
  18. efficient.
  19. *******************************************************************************/
  20. struct RXBUCKET
  21. {
  22. unsigned index : 13; // object array index (sprite[], sector[], wall[])
  23. unsigned type : 3; // 0=sprite, 1=sector, 2=wall
  24. } rxBucket[kMaxChannels];
  25. ushort bucketHead[kMaxID + 1];
  26. static int GetBucketChannel( RXBUCKET *pBucket )
  27. {
  28. int nXIndex;
  29. switch (pBucket->type)
  30. {
  31. case SS_SECTOR:
  32. nXIndex = sector[pBucket->index].extra;
  33. dassert(nXIndex > 0);
  34. return xsector[nXIndex].rxID;
  35. case SS_WALL:
  36. nXIndex = wall[pBucket->index].extra;
  37. dassert(nXIndex > 0);
  38. return xwall[nXIndex].rxID;
  39. case SS_SPRITE:
  40. nXIndex = sprite[pBucket->index].extra;
  41. dassert(nXIndex > 0);
  42. return xsprite[nXIndex].rxID;
  43. }
  44. ThrowError("Unexpected rxBucket type", ES_ERROR);
  45. return 0;
  46. }
  47. int CompareChannels( const void *ref1, const void *ref2 )
  48. {
  49. return GetBucketChannel((RXBUCKET *)ref1) - GetBucketChannel((RXBUCKET *)ref2);
  50. }
  51. /*******************************************************************************
  52. FUNCTION: evInit()
  53. DESCRIPTION: Initialize the event queue
  54. NOTES: The map should be loaded so that all the rxIDs can be
  55. scanned
  56. *******************************************************************************/
  57. void evInit( void )
  58. {
  59. int i, j;
  60. int nCount = 0;
  61. eventQ.Flush();
  62. // add all the tags to the bucket array
  63. for (i = 0; i < kMaxSectors; i++)
  64. {
  65. int nXSector = sector[i].extra;
  66. if (nXSector > 0 && xsector[nXSector].rxID > 0)
  67. {
  68. dassert(nCount < kMaxChannels);
  69. rxBucket[nCount].type = SS_SECTOR;
  70. rxBucket[nCount].index = i;
  71. nCount++;
  72. }
  73. }
  74. for (i = 0; i < kMaxWalls; i++)
  75. {
  76. int nXWall = wall[i].extra;
  77. if (nXWall > 0 && xwall[nXWall].rxID > 0)
  78. {
  79. dassert(nCount < kMaxChannels);
  80. rxBucket[nCount].type = SS_WALL;
  81. rxBucket[nCount].index = i;
  82. nCount++;
  83. }
  84. }
  85. for (i = 0; i < kMaxSprites; i++)
  86. {
  87. if (sprite[i].statnum < kMaxStatus)
  88. {
  89. int nXSprite = sprite[i].extra;
  90. if (nXSprite > 0 && xsprite[nXSprite].rxID > 0)
  91. {
  92. dassert(nCount < kMaxChannels);
  93. rxBucket[nCount].type = SS_SPRITE;
  94. rxBucket[nCount].index = i;
  95. nCount++;
  96. }
  97. }
  98. }
  99. // sort the array on rx tags
  100. qsort(rxBucket, nCount, sizeof(RXBUCKET), &CompareChannels);
  101. // create the list of header indices
  102. j = 0;
  103. for (i = 0; i < kMaxID; i++)
  104. {
  105. bucketHead[i] = (short)j;
  106. while ( j < nCount && GetBucketChannel(&rxBucket[j]) == i)
  107. j++;
  108. }
  109. bucketHead[i] = (short)j;
  110. }
  111. /***********************************************************************
  112. * evSourceState()
  113. *
  114. * Return the operational state of the event's source.
  115. *
  116. **********************************************************************/
  117. static BOOL evGetSourceState( int type, int nIndex )
  118. {
  119. int nXIndex;
  120. switch ( type )
  121. {
  122. case SS_SECTOR:
  123. nXIndex = sector[nIndex].extra;
  124. dassert(nXIndex > 0 && nXIndex < kMaxXSectors);
  125. return (BOOL)xsector[nXIndex].state;
  126. case SS_WALL:
  127. nXIndex = wall[nIndex].extra;
  128. dassert(nXIndex > 0 && nXIndex < kMaxXWalls);
  129. return (BOOL)xwall[nXIndex].state;
  130. case SS_SPRITE:
  131. nXIndex = sprite[nIndex].extra;
  132. dassert(nXIndex > 0 && nXIndex < kMaxXSprites);
  133. return (BOOL)xsprite[nXIndex].state;
  134. }
  135. // shouldn't reach this point
  136. return FALSE;
  137. }
  138. /***********************************************************************
  139. * evSend()
  140. *
  141. **********************************************************************/
  142. void evSend( int index, int type, int to, int command )
  143. {
  144. if ( command == kCommandState )
  145. command = evGetSourceState(type, index) ? kCommandOn : kCommandOff;
  146. else if ( command == kCommandNotState )
  147. command = evGetSourceState(type, index) ? kCommandOff : kCommandOn;
  148. EVENT event;
  149. event.index = index;
  150. event.type = type;
  151. event.to = to;
  152. event.command = command;
  153. // handle transmit-only system triggers
  154. if (to > kChannelNull)
  155. {
  156. switch (to)
  157. {
  158. // case kChannelNull:
  159. // ThrowError("Event with null tag encountered", ES_ERROR);
  160. case kChannelEndLevelA:
  161. gEndLevelFlag = gEndingA;
  162. // Hooray. You finished the level.
  163. return;
  164. case kChannelEndLevelB:
  165. gEndLevelFlag = gEndingB;
  166. // Hooray. You finished the level via the secret ending.
  167. return;
  168. case kChannelTextOver:
  169. if (command < kCommandNumbered)
  170. ThrowError("Non-numbered command triggered for TextOver", ES_ERROR);
  171. trTextOver(command - kCommandNumbered);
  172. return;
  173. case kChannelLightning:
  174. if (command < kCommandNumbered)
  175. ThrowError("Non-numbered command triggered for Lightning", ES_ERROR);
  176. trLightning(command - kCommandNumbered);
  177. return;
  178. case kChannelTriggerStart:
  179. dprintf("Trigger start broadcast\n");
  180. break;
  181. case kChannelTriggerMatch:
  182. dprintf("BloodBath start broadcast\n");
  183. break;
  184. case kChannelTriggerCoop:
  185. dprintf("Coop start broadcast\n");
  186. break;
  187. case kChannelRemoteFire1:
  188. case kChannelRemoteFire2:
  189. case kChannelRemoteFire3:
  190. case kChannelRemoteFire4:
  191. case kChannelRemoteFire5:
  192. case kChannelRemoteFire6:
  193. case kChannelRemoteFire7:
  194. case kChannelRemoteFire8:
  195. // these can't use the rx buckets since they are dynamically created
  196. for (short nSprite = headspritestat[kStatThing]; nSprite >= 0; nSprite = nextspritestat[nSprite] )
  197. {
  198. SPRITE *pSprite = &sprite[nSprite];
  199. if ( pSprite->extra > 0 )
  200. {
  201. XSPRITE *pXSprite = &xsprite[pSprite->extra];
  202. if ( pXSprite->rxID == to )
  203. trMessageSprite( nSprite, event );
  204. }
  205. }
  206. return;
  207. }
  208. }
  209. // the event is a broadcast message
  210. for (int i = bucketHead[event.to]; i < bucketHead[event.to + 1]; i++)
  211. {
  212. // don't send it to the originator
  213. if (rxBucket[i].type == event.type && rxBucket[i].index == event.index)
  214. continue;
  215. switch ( rxBucket[i].type )
  216. {
  217. case SS_SECTOR:
  218. trMessageSector( rxBucket[i].index, event );
  219. break;
  220. case SS_WALL:
  221. trMessageWall( rxBucket[i].index, event );
  222. break;
  223. case SS_SPRITE:
  224. trMessageSprite( rxBucket[i].index, event );
  225. break;
  226. default:
  227. break;
  228. }
  229. }
  230. }
  231. /***********************************************************************
  232. * evPost()
  233. *
  234. **********************************************************************/
  235. void evPost( int index, int type, ulong time, int command )
  236. {
  237. if ( command == kCommandState )
  238. command = evGetSourceState(type, index) ? kCommandOn : kCommandOff;
  239. else if ( command == kCommandNotState )
  240. command = evGetSourceState(type, index) ? kCommandOff : kCommandOn;
  241. EVENT event;
  242. event.index = index;
  243. event.type = type;
  244. event.command = command;
  245. eventQ.Insert(gFrameClock + time, (void *&)event);
  246. }
  247. /***********************************************************************
  248. * evProcess()
  249. *
  250. * check for and process broadcast commands to objects
  251. *
  252. **********************************************************************/
  253. void evProcess( ulong time )
  254. {
  255. // while there are events to be processed
  256. while ( eventQ.Check(time) )
  257. {
  258. void *p = eventQ.Remove();
  259. EVENT event = (EVENT &)p;
  260. // is it a special callback event?
  261. // if (event.command != kCommandCallback)
  262. // ThrowError("Non-callback in event queue", ES_ERROR);
  263. dprintf("Dispatching callback event ");
  264. switch ( event.type )
  265. {
  266. case SS_SECTOR:
  267. dprintf("to sector %d\n", event.index);
  268. trMessageSector( event.index, event );
  269. break;
  270. case SS_WALL:
  271. dprintf("to wall %d\n", event.index);
  272. trMessageWall( event.index, event );
  273. break;
  274. case SS_SPRITE:
  275. dprintf("to sprite %d\n", event.index);
  276. trMessageSprite( event.index, event );
  277. break;
  278. }
  279. }
  280. }