- More compact code for event redirection

- Fix demo desync
- Fix MINGW compile warnings
- Move custom start health from data4 to sysData2 in gModern maps
- Proper respawn for custom dude

# Conflicts:
#	source/blood/src/dude.cpp
#	source/blood/src/dude.h
This commit is contained in:
NoOneBlood 2020-04-07 23:30:00 +03:00 committed by Christoph Oelckers
parent 64de30209b
commit e3e805b24c
8 changed files with 172 additions and 162 deletions

View file

@ -2469,7 +2469,7 @@ void actInit(bool bSaveLoad) {
nnExtInitModernStuff(bSaveLoad);
}
#endif
for (int nSprite = headspritestat[kStatItem]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
switch (sprite[nSprite].type) {
case kItemWeaponVoodooDoll:
@ -2587,7 +2587,15 @@ void actInit(bool bSaveLoad) {
#endif
xvel[nSprite] = yvel[nSprite] = zvel[nSprite] = 0;
pXSprite->health = dudeGetStartHp(pSprite);
#ifdef NOONE_EXTENSIONS
// add a way to set custom hp for every enemy - should work only if map just started and not loaded.
if (!gModernMap || pXSprite->sysData2 <= 0) pXSprite->health = dudeInfo[nType].startHealth << 4;
else pXSprite->health = ClipRange(pXSprite->sysData2 << 4, 1, 65535);
#else
pXSprite->health = dudeInfo[nType].startHealth << 4;
#endif
}
if (gSysRes.Lookup(seqStartId, "SEQ")) seqSpawn(seqStartId, 3, pSprite->extra);

View file

@ -1647,7 +1647,9 @@ spritetype* genDudeSpawn(spritetype* pSprite, int nDist) {
if (pSource->clipdist > 0) pDude->clipdist = pSource->clipdist;
// inherit custom hp settings
pXDude->health = dudeGetStartHp(pDude);
if (pXSource->data4 <= 0) pXDude->health = dudeInfo[nType - kDudeBase].startHealth << 4;
else pXDude->health = ClipRange(pXSource->data4 << 4, 1, 65535);
if (pSource->flags & kModernTypeFlag1) {
switch (pSource->type) {
@ -1740,8 +1742,8 @@ void genDudeTransform(spritetype* pSprite) {
pXSprite->data1 = pXIncarnation->data1;
pXSprite->data2 = pXIncarnation->data2;
pXSprite->sysData1 = pXIncarnation->data3;
pXSprite->sysData2 = pXIncarnation->data4;
pXSprite->sysData1 = pXIncarnation->data3; // soundBase id
pXSprite->sysData2 = pXIncarnation->data4; // start hp
pXSprite->dudeGuard = pXIncarnation->dudeGuard;
pXSprite->dudeDeaf = pXIncarnation->dudeDeaf;
@ -1758,7 +1760,8 @@ void genDudeTransform(spritetype* pSprite) {
pXIncarnation->key = pXIncarnation->dropMsg = 0;
// set hp
pXSprite->health = dudeGetStartHp(pSprite);
if (pXSprite->sysData2 <= 0) pXSprite->health = dudeInfo[pSprite->type - kDudeBase].startHealth << 4;
else pXSprite->health = ClipRange(pXSprite->sysData2 << 4, 1, 65535);
int seqId = dudeInfo[pSprite->type - kDudeBase].seqStartID;
switch (pSprite->type) {

View file

@ -270,7 +270,9 @@ void Respawn(int nSprite) // 9
pSprite->y = baseSprite[nSprite].y;
pSprite->z = baseSprite[nSprite].z;
pSprite->cstat |= 0x1101;
pXSprite->health = dudeGetStartHp(pSprite);
#ifdef NOONE_EXTENSIONS
if (!gModernMap || pXSprite->sysData2 <= 0) pXSprite->health = dudeInfo[pSprite->type - kDudeBase].startHealth << 4;
else pXSprite->health = ClipRange(pXSprite->sysData2 << 4, 1, 65535);
switch (pSprite->type) {
default:
pSprite->clipdist = getDudeInfo(nType + kDudeBase)->clipdist;
@ -281,6 +283,12 @@ void Respawn(int nSprite) // 9
seqSpawn(genDudeSeqStartId(pXSprite), 3, pSprite->extra, -1);
break;
}
#else
pSprite->clipdist = getDudeInfo(nType + kDudeBase)->clipdist;
pXSprite->health = getDudeInfo(nType + kDudeBase)->startHealth << 4;
if (gSysRes.Lookup(getDudeInfo(nType + kDudeBase)->seqStartID, "SEQ"))
seqSpawn(getDudeInfo(nType + kDudeBase)->seqStartID, 3, pSprite->extra, -1);
#endif
aiInitSprite(pSprite);
pXSprite->key = 0;
} else if (pSprite->type == kThingTNTBarrel) {

View file

@ -1570,7 +1570,7 @@ DUDEINFO dudeInfo[kDudeMax-kDudeBase] =
256, // angSpeed
// 0,
7, -1, 18, // nGibType
64, 256, 256, 256, 256, 256, 256,
128, 150, 128, 256, 128, 128, 128,
0, 0, 0, 0, 0, 0, 0,
0,
0
@ -1732,20 +1732,4 @@ DUDEINFO gPlayerTemplate[4] =
};
DUDEINFO fakeDudeInfo = {};
int dudeGetStartHp(spritetype* pDude) {
int hp = getDudeInfo(pDude->type)->startHealth << 4;
if (!hp) {
consoleSysMsg("Sprite #%d (type %d) is not a dude!", pDude->index, pDude->type);
return hp;
}
#ifdef NOONE_EXTENSIONS
// add a way to set custom hp for every enemy (data4 moved to sysData2)
else if (gModernMap && xsprite[pDude->extra].sysData2 > 0)
hp = ClipRange(xsprite[pDude->extra].sysData2 << 4, 1, 65535);
#endif
return hp;
}
END_BLD_NS

View file

@ -66,6 +66,4 @@ inline DUDEINFO *getDudeInfo(int const nType)
return &fakeDudeInfo;
}
int dudeGetStartHp(spritetype* pDude);
END_BLD_NS

View file

@ -407,6 +407,7 @@ void nnExtInitModernStuff(bool bSaveLoad) {
if (sysStat)
ThrowError("Sprite #%d: System status list number %d detected!", pSprite->index, pSprite->statnum);
*/
switch (pSprite->type) {
case kModernRandomTX:
case kModernSequentialTX:
@ -729,7 +730,6 @@ void nnExtProcessSuperSprites() {
// process Debris sprites for movement
if (gPhysSpritesCount > 0) {
//viewSetSystemMessage("PHYS COUNT: %d", gPhysSpritesCount);
for (int i = 0; i < gPhysSpritesCount; i++) {
if (gPhysSpritesList[i] == -1) continue;
else if (sprite[gPhysSpritesList[i]].statnum == kStatFree || (sprite[gPhysSpritesList[i]].flags & kHitagFree) != 0) {
@ -1174,30 +1174,15 @@ void windGenStopWindOnSectors(XSPRITE* pXSource) {
pXSector->windVel = 0;
}
}
if (gEventRedirectsUsed) {
int rx = 0; XSPRITE* pXRedir = eventRedirected(OBJ_SPRITE, pSource->extra, false);
if (pXRedir == NULL) return;
else if (txIsRanged(pXRedir)) {
if (!channelRangeIsFine(pXRedir->data4 - pXRedir->data1)) return;
for (rx = pXRedir->data1; rx <= pXRedir->data4; rx++) {
for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) {
if (rxBucket[i].type != OBJ_SECTOR) continue;
XSECTOR* pXSector = &xsector[sector[rxBucket[i].index].extra];
if ((pXSector->state == 1 && !pXSector->windAlways) || (pSource->flags & kModernTypeFlag2))
pXSector->windVel = 0;
}
}
} else {
for (int i = 0; i <= 3; i++) {
if (!channelRangeIsFine((rx = GetDataVal(&sprite[pXRedir->reference], i)))) continue;
for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) {
if (rxBucket[i].type != OBJ_SECTOR) continue;
XSECTOR* pXSector = &xsector[sector[rxBucket[i].index].extra];
if ((pXSector->state == 1 && !pXSector->windAlways) || (pSource->flags & kModernTypeFlag2))
pXSector->windVel = 0;
}
}
// check redirected TX buckets
int rx = -1; XSPRITE* pXRedir = NULL;
while ((pXRedir = evrListRedirectors(OBJ_SPRITE, sprite[pXSource->reference].extra, pXRedir, &rx)) != NULL) {
for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) {
if (rxBucket[i].type != OBJ_SECTOR) continue;
XSECTOR* pXSector = &xsector[sector[rxBucket[i].index].extra];
if ((pXSector->state == 1 && !pXSector->windAlways) || (pSource->flags & kModernTypeFlag2))
pXSector->windVel = 0;
}
}
}
@ -1238,7 +1223,6 @@ void trPlayerCtrlStartScene(XSPRITE* pXSource, PLAYER* pPlayer) {
void trPlayerCtrlStopScene(XSPRITE* pXSource, PLAYER* pPlayer) {
TRPLAYERCTRL* pCtrl = &gPlayerCtrl[pPlayer->nPlayer];
//viewSetSystemMessage("OFF %d", pCtrl->qavScene.index);
pXSource->sysData1 = 0;
pCtrl->qavScene.index = -1;
@ -2204,6 +2188,9 @@ bool condCmp(int val, int arg1, int arg2, int comOp) {
// no extra comparison (val always = 0)?
bool condCmpne(int arg1, int arg2, int comOp) {
UNREFERENCED_PARAMETER(arg2);
if (comOp & 0x2000) return (comOp & CSTAT_SPRITE_BLOCK) ? false : (!arg1); // blue sprite
else if (comOp & 0x4000) return (comOp & CSTAT_SPRITE_BLOCK) ? false : (!arg1); // green sprite
else return (!arg1);
@ -2299,6 +2286,7 @@ bool condCheckMixed(XSPRITE* pXCond, EVENT event, int cmpOp, bool PUSH, bool RVR
break;
}
}
break;
case 41:
case 42:
case 43:
@ -2376,7 +2364,7 @@ bool condCheckSector(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS) {
int var = -1;
int cond = pXCond->data1 - kCondSectorBase; int arg1 = pXCond->data2;
int arg2 = pXCond->data3; int arg3 = pXCond->data4;
int arg2 = pXCond->data3; //int arg3 = pXCond->data4;
int objType = -1; int objIndex = -1;
condUnserialize(pXCond->targetX, &objType, &objIndex);
@ -2445,7 +2433,7 @@ bool condCheckWall(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS) {
int var = -1;
int cond = pXCond->data1 - kCondWallBase; int arg1 = pXCond->data2;
int arg2 = pXCond->data3; int arg3 = pXCond->data4;
int arg2 = pXCond->data3; //int arg3 = pXCond->data4;
int objType = -1; int objIndex = -1;
condUnserialize(pXCond->targetX, &objType, &objIndex);
@ -2454,7 +2442,7 @@ bool condCheckWall(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS) {
ThrowError("\nWall conditions:\nObject #%d (objType: %d) is not a wall!", objIndex, objType);
walltype* pWall = &wall[objIndex];
XWALL* pXWall = (xwallRangeIsFine(pWall->extra)) ? &xwall[pWall->extra] : NULL;
//XWALL* pXWall = (xwallRangeIsFine(pWall->extra)) ? &xwall[pWall->extra] : NULL;
if (cond < (kCondRange >> 1)) {
switch (cond) {
@ -2488,6 +2476,8 @@ bool condCheckWall(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS) {
bool condCheckDude(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS) {
UNREFERENCED_PARAMETER(RVRS);
int var = -1; PLAYER* pPlayer = NULL;
int cond = pXCond->data1 - kCondDudeBase; int arg1 = pXCond->data2;
int arg2 = pXCond->data3; int arg3 = pXCond->data4;
@ -2569,6 +2559,8 @@ bool condCheckDude(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS) {
bool condCheckSprite(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS) {
UNREFERENCED_PARAMETER(RVRS);
int var = -1; PLAYER* pPlayer = NULL; bool retn = false;
int cond = pXCond->data1 - kCondSpriteBase; int arg1 = pXCond->data2;
int arg2 = pXCond->data3; int arg3 = pXCond->data4;
@ -2666,7 +2658,7 @@ bool condCheckSprite(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS) {
switch (cond) {
default: break;
case 50: // compare hp (in %)
if (IsDudeSprite(pSpr)) var = dudeGetStartHp(pSpr);
if (IsDudeSprite(pSpr)) var = (pXSpr->sysData2 > 0) ? ClipRange(pXSpr->sysData2 << 4, 1, 65535) : getDudeInfo(pSpr->type)->startHealth << 4;
else if (condCmpne(arg1, arg2, cmpOp) && pSpr->type == kThingBloodChunks) return true;
else if (pSpr->type >= kThingBase && pSpr->type < kThingMax)
var = thingInfo[pSpr->type - kThingBase].startHealth << 4;
@ -2711,7 +2703,6 @@ bool condCheckSprite(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS) {
return condCmp(getSpriteMassBySize(pSpr), arg1, arg2, cmpOp); // mass of the sprite in a range?
}
} else {
viewSetSystemMessage("!!!!!!!! %d", pSpr->type);
switch (cond) {
default: return false;
case 50:
@ -2832,6 +2823,7 @@ void modernTypeTrigger(int destObjType, int destObjIndex, EVENT event) {
modernTypeSendCommand(pSource->index, pXSpr->txID, (COMMAND_ID)pXSource->command);
return;
}
break;
}
break;
default:
@ -2896,55 +2888,6 @@ void modernTypeTrigger(int destObjType, int destObjIndex, EVENT event) {
}
}
XSPRITE* eventRedirected(int objType, int objXIndex, bool byRx) {
unsigned short id = 0;
switch (objType) {
case OBJ_SECTOR:
if (!xsectRangeIsFine(objXIndex)) return NULL;
id = (byRx) ? xsector[objXIndex].rxID : xsector[objXIndex].txID;
break;
case OBJ_SPRITE:
if (!xspriRangeIsFine(objXIndex)) return NULL;
id = (byRx) ? xsprite[objXIndex].rxID : xsprite[objXIndex].txID;
break;
case OBJ_WALL:
if (!xwallRangeIsFine(objXIndex)) return NULL;
id = (byRx) ? xwall[objXIndex].rxID : xwall[objXIndex].txID;
break;
default:
return NULL;
}
if (!byRx) {
for (int i = bucketHead[id]; i < bucketHead[id + 1]; i++) {
if (rxBucket[i].type != OBJ_SPRITE) continue;
spritetype* pSpr = &sprite[rxBucket[i].index];
if (!xspriRangeIsFine(pSpr->extra)) continue;
switch (pSpr->type) {
case kModernRandomTX:
case kModernSequentialTX:
XSPRITE* pXSpr = &xsprite[pSpr->extra];
if (!(pSpr->flags & kModernTypeFlag2) || pXSpr->locked) continue;
return pXSpr;
}
}
} else {
for (int nSprite = headspritestat[kStatModernEventRedirector]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
if (xspriRangeIsFine(sprite[nSprite].extra)) {
XSPRITE* pXRedir = &xsprite[sprite[nSprite].extra];
if (txIsRanged(pXRedir)) {
if (id >= pXRedir->data1 && id <= pXRedir->data4) return pXRedir;
} else {
for (int i = 0; i <= 3; i++)
if (id == GetDataVal(&sprite[pXRedir->reference], i)) return pXRedir;
}
}
}
}
return NULL;
}
// the following functions required for kModernDudeTargetChanger
//---------------------------------------
spritetype* aiFightGetTargetInRange(spritetype* pSprite, int minDist, int maxDist, short data, short teamMode) {
@ -3031,7 +2974,6 @@ bool aiFightDudeCanSeeTarget(XSPRITE* pXDude, DUDEINFO* pDudeInfo, spritetype* p
spritetype* pDude = &sprite[pXDude->reference];
int dx = pTarget->x - pDude->x; int dy = pTarget->y - pDude->y;
//viewSetSystemMessage("zzzz");
// check target
if (approxDist(dx, dy) < pDudeInfo->seeDist) {
int eyeAboveZ = pDudeInfo->eyeHeight * pDude->yrepeat << 2;
@ -3116,27 +3058,13 @@ bool aiFightGetDudesForBattle(XSPRITE* pXSprite) {
xsprite[sprite[rxBucket[i].index].extra].health > 0) return true;
}
if (gEventRedirectsUsed) {
int rx = 0; XSPRITE* pXRedir = eventRedirected(OBJ_SPRITE, sprite[pXSprite->reference].extra, false);
if (pXRedir == NULL) return false;
else if (txIsRanged(pXRedir)) {
if (!channelRangeIsFine(pXRedir->data4 - pXRedir->data1)) return false;
for (rx = pXRedir->data1; rx <= pXRedir->data4; rx++) {
for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) {
if (rxBucket[i].type != OBJ_SPRITE) continue;
else if (IsDudeSprite(&sprite[rxBucket[i].index]) &&
xsprite[sprite[rxBucket[i].index].extra].health > 0) return true;
}
}
} else {
for (int i = 0; i <= 3; i++) {
if (!channelRangeIsFine((rx = GetDataVal(&sprite[pXRedir->reference], i)))) continue;
for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) {
if (rxBucket[i].type != OBJ_SPRITE) continue;
else if (IsDudeSprite(&sprite[rxBucket[i].index]) &&
xsprite[sprite[rxBucket[i].index].extra].health > 0) return true;
}
}
// check redirected TX buckets
int rx = -1; XSPRITE* pXRedir = NULL;
while ((pXRedir = evrListRedirectors(OBJ_SPRITE, sprite[pXSprite->reference].extra, pXRedir, &rx)) != NULL) {
for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) {
if (rxBucket[i].type != OBJ_SPRITE) continue;
else if (IsDudeSprite(&sprite[rxBucket[i].index]) &&
xsprite[sprite[rxBucket[i].index].extra].health > 0) return true;
}
}
return false;
@ -3442,11 +3370,9 @@ bool modernTypeOperateSprite(int nSprite, spritetype* pSprite, XSPRITE* pXSprite
evPost(nSprite, 3, 0, kCmdOff);
break;
}
if (pXSprite->txID > 0 /*&& pXSprite->data1 > 0 && pXSprite->data1 <= 4*/) {
modernTypeSendCommand(nSprite, pXSprite->txID, (COMMAND_ID)pXSprite->command);
if (pXSprite->busyTime > 0) evPost(nSprite, 3, pXSprite->busyTime, kCmdRepeat);
}
modernTypeSendCommand(nSprite, pXSprite->txID, (COMMAND_ID)pXSprite->command);
if (pXSprite->busyTime > 0) evPost(nSprite, 3, pXSprite->busyTime, kCmdRepeat);
break;
default:
if (pXSprite->state == 0) evPost(nSprite, 3, 0, kCmdOn);
@ -4099,6 +4025,7 @@ void useIncDecGen(XSPRITE* pXSource, short objType, int objIndex) {
}
}
pXSource->sysData1 = data;
setDataValueOfObject(objType, objIndex, dataIndex, data);
}
@ -4196,11 +4123,10 @@ void useTargetChanger(XSPRITE* pXSource, spritetype* pSprite) {
if (pBurnSource->extra >= 0) {
if (pXSource->data2 == 1 && aiFightIsMateOf(pXSprite, &xsprite[pBurnSource->extra])) {
pXSprite->burnTime = 0;
// heal dude a bit in case of friendly fire
int startHp = dudeGetStartHp(pSprite);
int startHp = (pXSprite->sysData2 > 0) ? ClipRange(pXSprite->sysData2 << 4, 1, 65535) : pDudeInfo->startHealth << 4;
if (pXSprite->health < startHp) actHealDude(pXSprite, receiveHp, startHp);
} else if (xsprite[pBurnSource->extra].health <= 0) {
pXSprite->burnTime = 0;
}
@ -4266,11 +4192,11 @@ void useTargetChanger(XSPRITE* pXSource, spritetype* pSprite) {
spritetype* pMate = pTarget; XSPRITE* pXMate = pXTarget;
// heal dude
int startHp = dudeGetStartHp(pSprite);
int startHp = (pXSprite->sysData2 > 0) ? ClipRange(pXSprite->sysData2 << 4, 1, 65535) : pDudeInfo->startHealth << 4;
if (pXSprite->health < startHp) actHealDude(pXSprite, receiveHp, startHp);
// heal mate
startHp = dudeGetStartHp(pMate);
startHp = (pXMate->sysData2 > 0) ? ClipRange(pXMate->sysData2 << 4, 1, 65535) : getDudeInfo(pMate->type)->startHealth << 4;
if (pXMate->health < startHp) actHealDude(pXMate, receiveHp, startHp);
if (pXMate->target > -1 && sprite[pXMate->target].extra >= 0) {
@ -4750,44 +4676,114 @@ bool setDataValueOfObject(int objType, int objIndex, int dataIndex, int value) {
}
}
int listTx(XSPRITE* pXRedir, int tx) {
if (txIsRanged(pXRedir)) {
if (tx == -1) tx = pXRedir->data1;
else if (tx < pXRedir->data4) tx++;
else tx = -1;
} else {
if (tx == -1) {
for (int i = 0; i <= 3; i++) {
if ((tx = GetDataVal(&sprite[pXRedir->reference], i)) <= 0) continue;
else return tx;
}
} else {
int saved = tx; bool savedFound = false;
for (int i = 0; i <= 3; i++) {
tx = GetDataVal(&sprite[pXRedir->reference], i);
if (savedFound && tx > 0) return tx;
else if (tx != saved) continue;
else savedFound = true;
}
}
tx = -1;
}
return tx;
}
XSPRITE* evrIsRedirector(int nSprite) {
if (spriRangeIsFine(nSprite)) {
switch (sprite[nSprite].type) {
case kModernRandomTX:
case kModernSequentialTX:
if ((sprite[nSprite].flags & kModernTypeFlag2)
&& xspriRangeIsFine(sprite[nSprite].extra) && !xsprite[sprite[nSprite].extra].locked) {
return &xsprite[sprite[nSprite].extra];
}
break;
}
}
return NULL;
}
XSPRITE* evrListRedirectors(int objType, int objXIndex, XSPRITE* pXRedir, int* tx) {
if (!gEventRedirectsUsed) return NULL;
else if (pXRedir && (*tx = listTx(pXRedir, *tx)) != -1)
return pXRedir;
int id = 0;
switch (objType) {
case OBJ_SECTOR:
if (!xsectRangeIsFine(objXIndex)) return NULL;
id = xsector[objXIndex].txID;
break;
case OBJ_SPRITE:
if (!xspriRangeIsFine(objXIndex)) return NULL;
id = xsprite[objXIndex].txID;
break;
case OBJ_WALL:
if (!xwallRangeIsFine(objXIndex)) return NULL;
id = xwall[objXIndex].txID;
break;
default:
return NULL;
}
int nIndex = (pXRedir) ? pXRedir->reference : -1; bool prevFound = false;
for (int i = bucketHead[id]; i < bucketHead[id + 1]; i++) {
if (rxBucket[i].type != OBJ_SPRITE) continue;
XSPRITE* pXSpr = evrIsRedirector(rxBucket[i].index);
if (!pXSpr) continue;
else if (prevFound || nIndex == -1) { *tx = listTx(pXSpr, *tx); return pXSpr; }
else if (nIndex != pXSpr->reference) continue;
else prevFound = true;
}
*tx = -1;
return NULL;
}
// this function checks if all TX objects have the same value
bool incDecGoalValueIsReached(XSPRITE* pXSprite) {
char buffer[5]; sprintf(buffer, "%d", abs(pXSprite->data1)); int len = strlen(buffer); int rx = 0;
XSPRITE* pXRedir = (gEventRedirectsUsed) ? eventRedirected(OBJ_SPRITE, sprite[pXSprite->reference].extra, false) : NULL;
if (pXSprite->data3 != pXSprite->sysData1) return false;
char buffer[5]; sprintf(buffer, "%d", abs(pXSprite->data1)); int len = strlen(buffer); int rx = -1;
for (int i = bucketHead[pXSprite->txID]; i < bucketHead[pXSprite->txID + 1]; i++) {
if (pXRedir && sprite[pXRedir->reference].index == (int) rxBucket[i].index) continue;
if (rxBucket[i].type == OBJ_SPRITE && evrIsRedirector(rxBucket[i].index)) continue;
for (int a = 0; a < len; a++) {
if (getDataFieldOfObject(rxBucket[i].type, rxBucket[i].index, (buffer[a] - 52) + 4) != pXSprite->data3)
return false;
}
}
if (pXRedir == NULL) return true;
else if (txIsRanged(pXRedir)) {
if (!channelRangeIsFine(pXRedir->data4 - pXRedir->data1)) return false;
for (rx = pXRedir->data1; rx <= pXRedir->data4; rx++) {
for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) {
for (int a = 0; a < len; i++) {
if (getDataFieldOfObject(rxBucket[i].type, rxBucket[i].index, (buffer[a] - 52) + 4) != pXSprite->data3)
return false;
}
}
}
} else {
for (int i = 0; i <= 3; i++) {
if (!channelRangeIsFine((rx = GetDataVal(&sprite[pXRedir->reference], i)))) continue;
for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) {
for (int a = 0; a < len; a++) {
if (getDataFieldOfObject(rxBucket[i].type, rxBucket[i].index, (buffer[a] - 52) + 4) != pXSprite->data3)
return false;
}
XSPRITE* pXRedir = NULL; // check redirected TX buckets
while ((pXRedir = evrListRedirectors(OBJ_SPRITE, sprite[pXSprite->reference].extra, pXRedir, &rx)) != NULL) {
for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) {
for (int a = 0; a < len; a++) {
if (getDataFieldOfObject(rxBucket[i].type, rxBucket[i].index, (buffer[a] - 52) + 4) != pXSprite->data3)
return false;
}
}
}
return true;
}
// this function can be called via sending numbered command to TX kChannelModernEndLevelCustom
// it allows to set custom next level instead of taking it from INI file.
void levelEndLevelCustom(int nLevel) {

View file

@ -328,7 +328,6 @@ void windGenStopWindOnSectors(XSPRITE* pXSource);
int getSpriteMassBySize(spritetype* pSprite);
bool ceilIsTooLow(spritetype* pSprite);
void levelEndLevelCustom(int nLevel);
XSPRITE* eventRedirected(int objType, int objXIndex, bool byRx);
bool useCondition(XSPRITE* pXSource, EVENT event);
bool condPush(XSPRITE* pXSprite, int objType, int objIndex);
bool condRestore(XSPRITE* pXSprite);
@ -339,6 +338,9 @@ bool condCheckSector(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS);
bool condCheckWall(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS);
bool condCheckSprite(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS);
void condUpdateObjectIndex(int objType, int oldIndex, int newIndex);
XSPRITE* evrListRedirectors(int objType, int objXIndex, XSPRITE* pXRedir, int* tx);
XSPRITE* evrIsRedirector(int nSprite);
int listTx(XSPRITE* pXRedir, int tx);
#endif
////////////////////////////////////////////////////////////////////////

View file

@ -332,8 +332,19 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
spritetype *pSprite = &sprite[nSprite];
#ifdef NOONE_EXTENSIONS
if (gModernMap && modernTypeOperateSprite(nSprite, pSprite, pXSprite, event))
if (gModernMap && modernTypeOperateSprite(nSprite, pSprite, pXSprite, event))
return;
switch (event.cmd) {
case kCmdLock:
pXSprite->locked = 1;
return;
case kCmdUnlock:
pXSprite->locked = 0;
return;
case kCmdToggleLock:
pXSprite->locked = pXSprite->locked ^ 1;
return;
}
#else
switch (event.cmd) {
case kCmdLock: