2019-09-19 22:42:45 +00:00
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
/*
|
|
|
|
|
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
|
|
|
|
Copyright (C) 2019 Nuke.YKT
|
2020-11-21 14:09:38 +00:00
|
|
|
|
Copyright (C) 2020 Christoph Oelckers
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
This file is part of Raze.
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
Raze is free software; you can redistribute it and/or
|
2019-09-19 22:42:45 +00:00
|
|
|
|
modify it under the terms of the GNU General Public License version 2
|
|
|
|
|
as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
*/
|
|
|
|
|
//-------------------------------------------------------------------------
|
2019-09-21 18:59:54 +00:00
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
#include "ns.h"
|
2020-11-08 08:47:32 +00:00
|
|
|
|
#include <set>
|
2019-09-19 22:42:45 +00:00
|
|
|
|
#include "build.h"
|
2020-11-21 14:09:38 +00:00
|
|
|
|
#include "printf.h"
|
2020-12-09 14:56:32 +00:00
|
|
|
|
#include "blood.h"
|
2019-11-12 23:44:33 +00:00
|
|
|
|
#include "secrets.h"
|
2020-11-21 14:09:38 +00:00
|
|
|
|
#include "serializer.h"
|
2020-12-03 17:00:07 +00:00
|
|
|
|
#include "bloodactor.h"
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
2019-09-22 06:39:22 +00:00
|
|
|
|
BEGIN_BLD_NS
|
|
|
|
|
|
2020-11-08 08:47:32 +00:00
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
const int kMaxID = 1024;
|
|
|
|
|
RXBUCKET rxBucket[kChannelMax];
|
|
|
|
|
unsigned short bucketHead[kMaxID + 1];
|
|
|
|
|
static int bucketCount;
|
|
|
|
|
static std::multiset<EVENT> queue;
|
2020-11-08 08:47:32 +00:00
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
2020-11-08 08:47:32 +00:00
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
static int GetBucketChannel(const RXBUCKET* pBucket)
|
2019-09-19 22:42:45 +00:00
|
|
|
|
{
|
2020-11-21 14:09:38 +00:00
|
|
|
|
int nXIndex;
|
|
|
|
|
switch (pBucket->type)
|
|
|
|
|
{
|
|
|
|
|
case SS_SECTOR:
|
2021-09-01 17:29:48 +00:00
|
|
|
|
nXIndex = sector[pBucket->rxindex].extra;
|
2020-11-21 14:09:38 +00:00
|
|
|
|
assert(nXIndex > 0);
|
|
|
|
|
return xsector[nXIndex].rxID;
|
|
|
|
|
|
|
|
|
|
case SS_WALL:
|
2021-09-01 17:29:48 +00:00
|
|
|
|
nXIndex = wall[pBucket->rxindex].extra;
|
2020-11-21 14:09:38 +00:00
|
|
|
|
assert(nXIndex > 0);
|
|
|
|
|
return xwall[nXIndex].rxID;
|
|
|
|
|
|
|
|
|
|
case SS_SPRITE:
|
2021-09-01 17:48:33 +00:00
|
|
|
|
return pBucket->GetActor()? pBucket->GetActor()->x().rxID : 0;
|
2020-11-21 14:09:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Printf(PRINT_HIGH, "Unexpected rxBucket type %d", pBucket->type);
|
|
|
|
|
return 0;
|
2019-09-19 22:42:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
static int CompareChannels(const RXBUCKET* ref1, const RXBUCKET* ref2)
|
2019-09-19 22:42:45 +00:00
|
|
|
|
{
|
2020-11-21 14:09:38 +00:00
|
|
|
|
return GetBucketChannel(ref1) - GetBucketChannel(ref2);
|
2019-09-19 22:42:45 +00:00
|
|
|
|
}
|
2020-11-21 14:09:38 +00:00
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
static RXBUCKET* SortGetMiddle(RXBUCKET* a1, RXBUCKET* a2, RXBUCKET* a3)
|
2019-09-19 22:42:45 +00:00
|
|
|
|
{
|
2020-11-21 14:09:38 +00:00
|
|
|
|
if (CompareChannels(a1, a2) > 0)
|
|
|
|
|
{
|
|
|
|
|
if (CompareChannels(a1, a3) > 0)
|
|
|
|
|
{
|
|
|
|
|
if (CompareChannels(a2, a3) > 0)
|
|
|
|
|
return a2;
|
|
|
|
|
return a3;
|
|
|
|
|
}
|
|
|
|
|
return a1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (CompareChannels(a1, a3) < 0)
|
|
|
|
|
{
|
|
|
|
|
if (CompareChannels(a2, a3) > 0)
|
|
|
|
|
return a3;
|
|
|
|
|
return a2;
|
|
|
|
|
}
|
|
|
|
|
return a1;
|
|
|
|
|
}
|
2019-09-19 22:42:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
static void SortSwap(RXBUCKET* a, RXBUCKET* b)
|
2019-09-19 22:42:45 +00:00
|
|
|
|
{
|
2020-11-21 14:09:38 +00:00
|
|
|
|
RXBUCKET t = *a;
|
|
|
|
|
*a = *b;
|
|
|
|
|
*b = t;
|
2019-09-19 22:42:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
static void SortRXBucket(int nCount)
|
2019-09-19 22:42:45 +00:00
|
|
|
|
{
|
2020-11-21 14:09:38 +00:00
|
|
|
|
RXBUCKET* v144[32];
|
|
|
|
|
int vc4[32];
|
|
|
|
|
int v14 = 0;
|
|
|
|
|
RXBUCKET* pArray = rxBucket;
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
while (nCount > 1)
|
|
|
|
|
{
|
|
|
|
|
if (nCount < 16)
|
|
|
|
|
{
|
|
|
|
|
for (int nDist = 3; nDist > 0; nDist -= 2)
|
|
|
|
|
{
|
|
|
|
|
for (RXBUCKET* pI = pArray + nDist; pI < pArray + nCount; pI += nDist)
|
|
|
|
|
{
|
|
|
|
|
for (RXBUCKET* pJ = pI; pJ > pArray && CompareChannels(pJ - nDist, pJ) > 0; pJ -= nDist)
|
|
|
|
|
{
|
|
|
|
|
SortSwap(pJ, pJ - nDist);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
RXBUCKET * middle = pArray + nCount / 2;
|
|
|
|
|
if (nCount > 29)
|
|
|
|
|
{
|
|
|
|
|
RXBUCKET* first = pArray;
|
|
|
|
|
RXBUCKET* last = pArray + nCount - 1;
|
|
|
|
|
if (nCount > 42)
|
|
|
|
|
{
|
|
|
|
|
int eighth = nCount / 8;
|
|
|
|
|
first = SortGetMiddle(first, first + eighth, first + eighth * 2);
|
|
|
|
|
middle = SortGetMiddle(middle - eighth, middle, middle + eighth);
|
|
|
|
|
last = SortGetMiddle(last - eighth * 2, last - eighth, last);
|
|
|
|
|
}
|
|
|
|
|
middle = SortGetMiddle(first, middle, last);
|
|
|
|
|
}
|
|
|
|
|
RXBUCKET pivot = *middle;
|
|
|
|
|
RXBUCKET* first = pArray;
|
|
|
|
|
RXBUCKET* last = pArray + nCount - 1;
|
|
|
|
|
RXBUCKET* vbx = first;
|
|
|
|
|
RXBUCKET* v4 = last;
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
while (vbx <= v4)
|
|
|
|
|
{
|
|
|
|
|
int nCmp = CompareChannels(vbx, &pivot);
|
|
|
|
|
if (nCmp > 0)
|
|
|
|
|
break;
|
|
|
|
|
if (nCmp == 0)
|
|
|
|
|
{
|
|
|
|
|
SortSwap(vbx, first);
|
|
|
|
|
first++;
|
|
|
|
|
}
|
|
|
|
|
vbx++;
|
|
|
|
|
}
|
|
|
|
|
while (vbx <= v4)
|
|
|
|
|
{
|
|
|
|
|
int nCmp = CompareChannels(v4, &pivot);
|
|
|
|
|
if (nCmp < 0)
|
|
|
|
|
break;
|
|
|
|
|
if (nCmp == 0)
|
|
|
|
|
{
|
|
|
|
|
SortSwap(v4, last);
|
|
|
|
|
last--;
|
|
|
|
|
}
|
|
|
|
|
v4--;
|
|
|
|
|
}
|
|
|
|
|
if (vbx > v4)
|
|
|
|
|
break;
|
|
|
|
|
SortSwap(vbx, v4);
|
|
|
|
|
v4--;
|
|
|
|
|
vbx++;
|
|
|
|
|
}
|
|
|
|
|
RXBUCKET* v2c = pArray + nCount;
|
2021-05-12 00:00:06 +00:00
|
|
|
|
int vt = int(min(vbx - first, first - pArray));
|
2020-11-21 14:09:38 +00:00
|
|
|
|
for (int i = 0; i < vt; i++)
|
|
|
|
|
{
|
|
|
|
|
SortSwap(&vbx[i - vt], &pArray[i]);
|
|
|
|
|
}
|
2021-05-12 00:00:06 +00:00
|
|
|
|
vt = int(min(last - v4, v2c - last - 1));
|
2020-11-21 14:09:38 +00:00
|
|
|
|
for (int i = 0; i < vt; i++)
|
|
|
|
|
{
|
|
|
|
|
SortSwap(&v2c[i - vt], &vbx[i]);
|
|
|
|
|
}
|
2021-05-12 00:00:06 +00:00
|
|
|
|
int vvsi = int(last - v4);
|
|
|
|
|
int vvdi = int(vbx - first);
|
2020-11-21 14:09:38 +00:00
|
|
|
|
if (vvsi >= vvdi)
|
|
|
|
|
{
|
|
|
|
|
vc4[v14] = vvsi;
|
|
|
|
|
v144[v14] = v2c - vvsi;
|
|
|
|
|
nCount = vvdi;
|
|
|
|
|
v14++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
vc4[v14] = vvdi;
|
|
|
|
|
v144[v14] = pArray;
|
|
|
|
|
nCount = vvsi;
|
|
|
|
|
pArray = v2c - vvsi;
|
|
|
|
|
v14++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (v14 == 0)
|
|
|
|
|
return;
|
|
|
|
|
v14--;
|
|
|
|
|
pArray = v144[v14];
|
|
|
|
|
nCount = vc4[v14];
|
|
|
|
|
}
|
2019-09-19 22:42:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
static void createBucketHeads()
|
2019-09-19 22:42:45 +00:00
|
|
|
|
{
|
2020-11-21 14:09:38 +00:00
|
|
|
|
int i, j;
|
|
|
|
|
// create the list of header indices
|
|
|
|
|
for (i = 0, j = 0; i < kMaxID; i++)
|
|
|
|
|
{
|
|
|
|
|
bucketHead[i] = (short)j;
|
|
|
|
|
while (j < bucketCount && GetBucketChannel(&rxBucket[j]) == i)
|
|
|
|
|
{
|
|
|
|
|
j++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
bucketHead[i] = (short)j;
|
2019-09-19 22:42:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
void evInit()
|
2019-09-19 22:42:45 +00:00
|
|
|
|
{
|
2020-11-21 14:09:38 +00:00
|
|
|
|
int nCount = 0;
|
|
|
|
|
|
|
|
|
|
queue.clear();
|
|
|
|
|
memset(rxBucket, 0, sizeof(rxBucket));
|
|
|
|
|
|
|
|
|
|
// add all the tags to the bucket array
|
|
|
|
|
for (int i = 0; i < numsectors; i++)
|
|
|
|
|
{
|
|
|
|
|
int nXSector = sector[i].extra;
|
|
|
|
|
if (nXSector > 0 && xsector[nXSector].rxID > 0)
|
|
|
|
|
{
|
|
|
|
|
assert(nCount < kChannelMax);
|
|
|
|
|
rxBucket[nCount].type = SS_SECTOR;
|
2021-09-01 17:29:48 +00:00
|
|
|
|
rxBucket[nCount].rxindex = i;
|
2020-11-21 14:09:38 +00:00
|
|
|
|
nCount++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < numwalls; i++)
|
|
|
|
|
{
|
|
|
|
|
int nXWall = wall[i].extra;
|
|
|
|
|
if (nXWall > 0 && xwall[nXWall].rxID > 0)
|
|
|
|
|
{
|
|
|
|
|
assert(nCount < kChannelMax);
|
|
|
|
|
rxBucket[nCount].type = SS_WALL;
|
2021-09-01 17:29:48 +00:00
|
|
|
|
rxBucket[nCount].rxindex = i;
|
2020-11-21 14:09:38 +00:00
|
|
|
|
nCount++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < kMaxSprites; i++)
|
|
|
|
|
{
|
|
|
|
|
if (sprite[i].statnum < kMaxStatus)
|
|
|
|
|
{
|
|
|
|
|
int nXSprite = sprite[i].extra;
|
|
|
|
|
if (nXSprite > 0 && xsprite[nXSprite].rxID > 0)
|
|
|
|
|
{
|
|
|
|
|
assert(nCount < kChannelMax);
|
|
|
|
|
rxBucket[nCount].type = SS_SPRITE;
|
2021-09-01 17:29:48 +00:00
|
|
|
|
rxBucket[nCount].rxindex = i;
|
2021-09-01 18:23:32 +00:00
|
|
|
|
rxBucket[nCount].actor = &bloodActors[i];
|
2020-11-21 14:09:38 +00:00
|
|
|
|
nCount++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SortRXBucket(nCount);
|
|
|
|
|
bucketCount = nCount;
|
|
|
|
|
createBucketHeads();
|
2019-09-19 22:42:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
static bool evGetSourceState(int type, int nIndex)
|
2019-09-19 22:42:45 +00:00
|
|
|
|
{
|
2020-11-21 14:09:38 +00:00
|
|
|
|
int nXIndex;
|
|
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case SS_SECTOR:
|
|
|
|
|
nXIndex = sector[nIndex].extra;
|
|
|
|
|
assert(nXIndex > 0 && nXIndex < kMaxXSectors);
|
|
|
|
|
return xsector[nXIndex].state != 0;
|
|
|
|
|
|
|
|
|
|
case SS_WALL:
|
|
|
|
|
nXIndex = wall[nIndex].extra;
|
|
|
|
|
assert(nXIndex > 0 && nXIndex < kMaxXWalls);
|
|
|
|
|
return xwall[nXIndex].state != 0;
|
|
|
|
|
|
|
|
|
|
case SS_SPRITE:
|
|
|
|
|
nXIndex = sprite[nIndex].extra;
|
|
|
|
|
assert(nXIndex > 0 && nXIndex < kMaxXSprites);
|
|
|
|
|
return xsprite[nXIndex].state != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// shouldn't reach this point
|
|
|
|
|
return false;
|
2019-09-19 22:42:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
2020-01-11 21:07:05 +00:00
|
|
|
|
void evSend(int nIndex, int nType, int rxId, COMMAND_ID command)
|
2019-09-19 22:42:45 +00:00
|
|
|
|
{
|
2020-11-21 14:09:38 +00:00
|
|
|
|
switch (command) {
|
|
|
|
|
case kCmdState:
|
|
|
|
|
command = evGetSourceState(nType, nIndex) ? kCmdOn : kCmdOff;
|
|
|
|
|
break;
|
|
|
|
|
case kCmdNotState:
|
|
|
|
|
command = evGetSourceState(nType, nIndex) ? kCmdOff : kCmdOn;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EVENT event;
|
2021-09-01 17:48:33 +00:00
|
|
|
|
event.actor = nType == SS_SPRITE? &bloodActors[nIndex] : nullptr;
|
2021-08-27 07:44:47 +00:00
|
|
|
|
event.index_ = nIndex;
|
2020-11-21 14:09:38 +00:00
|
|
|
|
event.type = nType;
|
|
|
|
|
event.cmd = command;
|
|
|
|
|
|
|
|
|
|
switch (rxId) {
|
|
|
|
|
case kChannelTextOver:
|
|
|
|
|
if (command >= kCmdNumberic) trTextOver(command - kCmdNumberic);
|
|
|
|
|
else viewSetSystemMessage("Invalid TextOver command by xobject #%d (object type %d)", nIndex, nType);
|
|
|
|
|
return;
|
|
|
|
|
case kChannelLevelExitNormal:
|
|
|
|
|
levelEndLevel(0);
|
|
|
|
|
return;
|
|
|
|
|
case kChannelLevelExitSecret:
|
|
|
|
|
levelEndLevel(1);
|
|
|
|
|
return;
|
|
|
|
|
#ifdef NOONE_EXTENSIONS
|
|
|
|
|
// finished level and load custom level <20> via numbered command.
|
|
|
|
|
case kChannelModernEndLevelCustom:
|
|
|
|
|
if (command >= kCmdNumberic) levelEndLevelCustom(command - kCmdNumberic);
|
|
|
|
|
else viewSetSystemMessage("Invalid Level-Exit# command by xobject #%d (object type %d)", nIndex, nType);
|
|
|
|
|
return;
|
|
|
|
|
#endif
|
|
|
|
|
case kChannelSetTotalSecrets:
|
2021-08-30 20:27:25 +00:00
|
|
|
|
if (command >= kCmdNumberic) gSecretMgr.SetCount(command - kCmdNumberic);
|
2020-11-21 14:09:38 +00:00
|
|
|
|
else viewSetSystemMessage("Invalid Total-Secrets command by xobject #%d (object type %d)", nIndex, nType);
|
|
|
|
|
break;
|
|
|
|
|
case kChannelSecretFound:
|
2020-12-01 11:49:24 +00:00
|
|
|
|
if (SECRET_Trigger(nIndex + 65536 * nType)) // if the hint system knows this secret it's a retrigger - skip that.
|
|
|
|
|
{
|
2021-08-30 20:27:25 +00:00
|
|
|
|
if (command >= kCmdNumberic)
|
|
|
|
|
{
|
|
|
|
|
gSecretMgr.Found(command - kCmdNumberic);
|
|
|
|
|
if (gGameOptions.nGameType == 0)
|
|
|
|
|
{
|
|
|
|
|
viewSetMessage(GStrings(FStringf("TXTB_SECRET%d", Random(2))), 0, MESSAGE_PRIORITY_SECRET);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-01 11:49:24 +00:00
|
|
|
|
else viewSetSystemMessage("Invalid Trigger-Secret command by xobject #%d (object type %d)", nIndex, nType);
|
|
|
|
|
}
|
2020-11-21 14:09:38 +00:00
|
|
|
|
break;
|
|
|
|
|
case kChannelRemoteBomb0:
|
|
|
|
|
case kChannelRemoteBomb1:
|
|
|
|
|
case kChannelRemoteBomb2:
|
|
|
|
|
case kChannelRemoteBomb3:
|
|
|
|
|
case kChannelRemoteBomb4:
|
|
|
|
|
case kChannelRemoteBomb5:
|
|
|
|
|
case kChannelRemoteBomb6:
|
|
|
|
|
case kChannelRemoteBomb7:
|
|
|
|
|
{
|
|
|
|
|
int nSprite;
|
|
|
|
|
StatIterator it(kStatThing);
|
|
|
|
|
while ((nSprite = it.NextIndex()) >= 0)
|
|
|
|
|
{
|
|
|
|
|
spritetype* pSprite = &sprite[nSprite];
|
|
|
|
|
if (pSprite->flags & 32)
|
|
|
|
|
continue;
|
|
|
|
|
int nXSprite = pSprite->extra;
|
|
|
|
|
if (nXSprite > 0)
|
|
|
|
|
{
|
|
|
|
|
XSPRITE* pXSprite = &xsprite[nXSprite];
|
|
|
|
|
if (pXSprite->rxID == rxId)
|
|
|
|
|
trMessageSprite(nSprite, event);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case kChannelTeamAFlagCaptured:
|
|
|
|
|
case kChannelTeamBFlagCaptured:
|
|
|
|
|
{
|
|
|
|
|
int nSprite;
|
|
|
|
|
StatIterator it(kStatItem);
|
|
|
|
|
while ((nSprite = it.NextIndex()) >= 0)
|
|
|
|
|
{
|
|
|
|
|
spritetype* pSprite = &sprite[nSprite];
|
|
|
|
|
if (pSprite->flags & 32)
|
|
|
|
|
continue;
|
|
|
|
|
int nXSprite = pSprite->extra;
|
|
|
|
|
if (nXSprite > 0)
|
|
|
|
|
{
|
|
|
|
|
XSPRITE* pXSprite = &xsprite[nXSprite];
|
|
|
|
|
if (pXSprite->rxID == rxId)
|
|
|
|
|
trMessageSprite(nSprite, event);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef NOONE_EXTENSIONS
|
|
|
|
|
if (gModernMap)
|
|
|
|
|
{
|
|
|
|
|
// allow to send commands on player sprites
|
|
|
|
|
PLAYER* pPlayer = NULL;
|
|
|
|
|
if (playerRXRngIsFine(rxId))
|
|
|
|
|
{
|
2020-12-06 20:56:09 +00:00
|
|
|
|
if ((pPlayer = getPlayerById((rxId - kChannelPlayer7) + kMaxPlayers)) != nullptr)
|
2020-11-21 14:09:38 +00:00
|
|
|
|
trMessageSprite(pPlayer->nSprite, event);
|
|
|
|
|
}
|
|
|
|
|
else if (rxId == kChannelAllPlayers)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < kMaxPlayers; i++)
|
|
|
|
|
{
|
|
|
|
|
if ((pPlayer = getPlayerById(i)) != nullptr)
|
|
|
|
|
trMessageSprite(pPlayer->nSprite, event);
|
|
|
|
|
}
|
2020-12-06 20:56:09 +00:00
|
|
|
|
return;
|
2020-11-21 14:09:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
for (int i = bucketHead[rxId]; i < bucketHead[rxId + 1]; i++)
|
|
|
|
|
{
|
2021-08-27 07:44:47 +00:00
|
|
|
|
if (event.type != rxBucket[i].type || (event.type != OBJ_SPRITE && event.index_ != rxBucket[i].rxindex) || (event.type == OBJ_SPRITE && event.actor != rxBucket[i].GetActor()))
|
2020-11-21 14:09:38 +00:00
|
|
|
|
{
|
|
|
|
|
switch (rxBucket[i].type)
|
|
|
|
|
{
|
|
|
|
|
case 6:
|
2021-09-01 17:29:48 +00:00
|
|
|
|
trMessageSector(rxBucket[i].rxindex, event);
|
2020-11-21 14:09:38 +00:00
|
|
|
|
break;
|
|
|
|
|
case 0:
|
2021-09-01 17:29:48 +00:00
|
|
|
|
trMessageWall(rxBucket[i].rxindex, event);
|
2020-11-21 14:09:38 +00:00
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
{
|
2021-09-01 17:48:33 +00:00
|
|
|
|
auto actor = rxBucket[i].GetActor();
|
|
|
|
|
|
|
|
|
|
if (actor && actor->hasX() && !(actor->s().flags & 32))
|
2020-11-21 14:09:38 +00:00
|
|
|
|
{
|
2021-09-01 17:48:33 +00:00
|
|
|
|
XSPRITE* pXSprite = &actor->x();
|
|
|
|
|
if (actor->x().rxID > 0)
|
|
|
|
|
trMessageSprite(actor->s().index, event);
|
2020-11-21 14:09:38 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-19 22:42:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
2021-08-26 20:02:55 +00:00
|
|
|
|
void evPost_(int nIndex, int nType, unsigned int nDelta, COMMAND_ID command)
|
2020-11-21 14:09:38 +00:00
|
|
|
|
{
|
|
|
|
|
assert(command != kCmdCallback);
|
|
|
|
|
if (command == kCmdState) command = evGetSourceState(nType, nIndex) ? kCmdOn : kCmdOff;
|
|
|
|
|
else if (command == kCmdNotState) command = evGetSourceState(nType, nIndex) ? kCmdOff : kCmdOn;
|
2021-09-01 19:57:11 +00:00
|
|
|
|
EVENT evn = {nullptr, (int16_t)nIndex, (int8_t)nType, (int8_t)command, 0, PlayClock + (int)nDelta };
|
2020-11-21 14:09:38 +00:00
|
|
|
|
queue.insert(evn);
|
2019-09-19 22:42:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-26 20:02:55 +00:00
|
|
|
|
void evPost_(int nIndex, int nType, unsigned int nDelta, CALLBACK_ID callback)
|
2019-09-19 22:42:45 +00:00
|
|
|
|
{
|
2021-09-01 19:57:11 +00:00
|
|
|
|
EVENT evn = {nullptr, (int16_t)nIndex, (int8_t)nType, kCmdCallback, (int16_t)callback, PlayClock + (int)nDelta };
|
2020-11-21 14:09:38 +00:00
|
|
|
|
queue.insert(evn);
|
2019-09-19 22:42:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
|
2021-08-27 07:44:47 +00:00
|
|
|
|
void evPostActor(DBloodActor* actor, unsigned int nDelta, COMMAND_ID command)
|
2020-12-03 17:00:07 +00:00
|
|
|
|
{
|
2021-08-26 20:02:55 +00:00
|
|
|
|
evPost_(actor->s().index, OBJ_SPRITE, nDelta, command);
|
2020-12-03 17:00:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-27 07:44:47 +00:00
|
|
|
|
void evPostActor(DBloodActor* actor, unsigned int nDelta, CALLBACK_ID callback)
|
2020-12-03 17:00:07 +00:00
|
|
|
|
{
|
2021-08-26 20:02:55 +00:00
|
|
|
|
evPost_(actor->s().index, OBJ_SPRITE, nDelta, callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void evPostSector(int index, unsigned int nDelta, COMMAND_ID command)
|
|
|
|
|
{
|
|
|
|
|
evPost_(index, OBJ_SECTOR, nDelta, command);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void evPostSector(int index, unsigned int nDelta, CALLBACK_ID callback)
|
|
|
|
|
{
|
|
|
|
|
evPost_(index, OBJ_SECTOR, nDelta, callback);
|
2020-12-03 17:00:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-27 08:18:33 +00:00
|
|
|
|
void evPostWall(int index, unsigned int nDelta, COMMAND_ID command)
|
|
|
|
|
{
|
|
|
|
|
evPost_(index, OBJ_WALL, nDelta, command);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
2021-09-01 19:57:11 +00:00
|
|
|
|
void evKill_(int index, int type)
|
2019-09-19 22:42:45 +00:00
|
|
|
|
{
|
2020-11-21 14:09:38 +00:00
|
|
|
|
for (auto ev = queue.begin(); ev != queue.end();)
|
|
|
|
|
{
|
2021-08-27 07:44:47 +00:00
|
|
|
|
if (ev->index_ == index && ev->type == type) ev = queue.erase(ev);
|
2020-11-21 14:09:38 +00:00
|
|
|
|
else ev++;
|
|
|
|
|
}
|
2019-09-19 22:42:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-01 19:57:11 +00:00
|
|
|
|
void evKill_(int index, int type, CALLBACK_ID cb)
|
2019-09-19 22:42:45 +00:00
|
|
|
|
{
|
2020-11-21 14:09:38 +00:00
|
|
|
|
for (auto ev = queue.begin(); ev != queue.end();)
|
|
|
|
|
{
|
2021-08-27 07:44:47 +00:00
|
|
|
|
if (ev->index_ == index && ev->type == type && ev->funcID == cb) ev = queue.erase(ev);
|
2020-11-21 14:09:38 +00:00
|
|
|
|
else ev++;
|
|
|
|
|
}
|
2019-09-19 22:42:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-27 07:44:47 +00:00
|
|
|
|
void evKillActor(DBloodActor* actor)
|
2020-12-03 17:00:07 +00:00
|
|
|
|
{
|
2021-09-01 19:57:11 +00:00
|
|
|
|
evKill_(actor->s().index, 3);
|
2020-12-03 17:00:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-27 07:44:47 +00:00
|
|
|
|
void evKillActor(DBloodActor* actor, CALLBACK_ID cb)
|
2021-09-16 17:42:54 +00:00
|
|
|
|
{
|
2021-09-01 19:57:11 +00:00
|
|
|
|
evKill_(actor->s().index, 3, cb);
|
2021-09-16 17:42:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-27 08:18:33 +00:00
|
|
|
|
void evKillWall(int wal)
|
|
|
|
|
{
|
|
|
|
|
evKill_(wal, OBJ_WALL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void evKillSector(int sec)
|
|
|
|
|
{
|
|
|
|
|
evKill_(sec, OBJ_SECTOR);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-27 08:46:57 +00:00
|
|
|
|
// these have no target.
|
|
|
|
|
void evSendGame(int rxId, COMMAND_ID command)
|
|
|
|
|
{
|
|
|
|
|
evSend(0, 0, rxId, command);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void evSendActor(DBloodActor* actor, int rxId, COMMAND_ID command)
|
|
|
|
|
{
|
|
|
|
|
evSend(actor->s().index, OBJ_SPRITE, rxId, command);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void evSendSector(int index, int rxId, COMMAND_ID command)
|
|
|
|
|
{
|
|
|
|
|
evSend(index, OBJ_SECTOR, rxId, command);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void evSendWall(int index, int rxId, COMMAND_ID command)
|
|
|
|
|
{
|
|
|
|
|
evSend(index, OBJ_WALL, rxId, command);
|
|
|
|
|
}
|
2021-08-27 08:18:33 +00:00
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void evProcess(unsigned int time)
|
2019-09-19 22:42:45 +00:00
|
|
|
|
{
|
2020-12-31 14:48:42 +00:00
|
|
|
|
while (queue.size() > 0 && (int)time >= queue.begin()->priority)
|
2020-11-21 14:09:38 +00:00
|
|
|
|
{
|
|
|
|
|
EVENT event = *queue.begin();
|
|
|
|
|
queue.erase(queue.begin());
|
|
|
|
|
|
|
|
|
|
if (event.cmd == kCmdCallback)
|
|
|
|
|
{
|
|
|
|
|
assert(event.funcID < kCallbackMax);
|
|
|
|
|
assert(gCallback[event.funcID] != nullptr);
|
2021-08-27 07:44:47 +00:00
|
|
|
|
if (event.type == OBJ_SPRITE) gCallback[event.funcID](&bloodActors[event.index_], 0);
|
|
|
|
|
else gCallback[event.funcID](nullptr, event.index_);
|
2020-11-21 14:09:38 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch (event.type)
|
|
|
|
|
{
|
|
|
|
|
case SS_SECTOR:
|
2021-08-27 07:44:47 +00:00
|
|
|
|
trMessageSector(event.index_, event);
|
2020-11-21 14:09:38 +00:00
|
|
|
|
break;
|
|
|
|
|
case SS_WALL:
|
2021-08-27 07:44:47 +00:00
|
|
|
|
trMessageWall(event.index_, event);
|
2020-11-21 14:09:38 +00:00
|
|
|
|
break;
|
|
|
|
|
case SS_SPRITE:
|
2021-08-27 07:44:47 +00:00
|
|
|
|
trMessageSprite(event.index_, event);
|
2020-11-21 14:09:38 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, EVENT& w, EVENT* def)
|
2019-09-19 22:42:45 +00:00
|
|
|
|
{
|
2020-11-21 14:09:38 +00:00
|
|
|
|
if (arc.BeginObject(keyname))
|
|
|
|
|
{
|
2021-08-27 07:44:47 +00:00
|
|
|
|
arc("index", w.index_)
|
2020-11-21 14:09:38 +00:00
|
|
|
|
("type", w.type)
|
|
|
|
|
("command", w.cmd)
|
|
|
|
|
("func", w.funcID)
|
|
|
|
|
("prio", w.priority)
|
|
|
|
|
.EndObject();
|
|
|
|
|
}
|
|
|
|
|
return arc;
|
2019-09-19 22:42:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, RXBUCKET& w, RXBUCKET* def)
|
2019-09-19 22:42:45 +00:00
|
|
|
|
{
|
2020-11-21 14:09:38 +00:00
|
|
|
|
if (arc.BeginObject(keyname))
|
|
|
|
|
{
|
2021-09-01 17:29:48 +00:00
|
|
|
|
arc("index", w.rxindex)
|
2020-11-21 14:09:38 +00:00
|
|
|
|
("type", w.type)
|
|
|
|
|
.EndObject();
|
|
|
|
|
}
|
|
|
|
|
return arc;
|
2019-09-19 22:42:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
2019-09-19 22:42:45 +00:00
|
|
|
|
|
2020-11-21 14:09:38 +00:00
|
|
|
|
void SerializeEvents(FSerializer& arc)
|
2019-09-19 22:42:45 +00:00
|
|
|
|
{
|
2020-11-21 14:09:38 +00:00
|
|
|
|
if (arc.BeginObject("events"))
|
|
|
|
|
{
|
|
|
|
|
arc("bucketcount", bucketCount)
|
2020-11-27 22:34:36 +00:00
|
|
|
|
.Array("buckets", rxBucket, bucketCount)
|
|
|
|
|
.Array("buckethead", bucketHead, countof(bucketHead));
|
2020-11-21 14:09:38 +00:00
|
|
|
|
|
|
|
|
|
int numEvents = (int)queue.size();
|
|
|
|
|
arc("eventcount", numEvents);
|
|
|
|
|
if (arc.BeginArray("events"))
|
|
|
|
|
{
|
|
|
|
|
if (arc.isReading())
|
|
|
|
|
{
|
|
|
|
|
queue.clear();
|
|
|
|
|
EVENT ev;
|
|
|
|
|
for (int i = 0; i < numEvents; i++)
|
|
|
|
|
{
|
|
|
|
|
arc(nullptr, ev);
|
|
|
|
|
queue.insert(ev);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (auto item : queue)
|
|
|
|
|
{
|
|
|
|
|
arc(nullptr, item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
arc.EndArray();
|
|
|
|
|
}
|
|
|
|
|
arc.EndObject();
|
|
|
|
|
}
|
2019-09-19 22:42:45 +00:00
|
|
|
|
}
|
2019-09-22 06:39:22 +00:00
|
|
|
|
|
|
|
|
|
END_BLD_NS
|