- 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); nnExtInitModernStuff(bSaveLoad);
} }
#endif #endif
for (int nSprite = headspritestat[kStatItem]; nSprite >= 0; nSprite = nextspritestat[nSprite]) { for (int nSprite = headspritestat[kStatItem]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
switch (sprite[nSprite].type) { switch (sprite[nSprite].type) {
case kItemWeaponVoodooDoll: case kItemWeaponVoodooDoll:
@ -2587,7 +2587,15 @@ void actInit(bool bSaveLoad) {
#endif #endif
xvel[nSprite] = yvel[nSprite] = zvel[nSprite] = 0; 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); 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; if (pSource->clipdist > 0) pDude->clipdist = pSource->clipdist;
// inherit custom hp settings // 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) { if (pSource->flags & kModernTypeFlag1) {
switch (pSource->type) { switch (pSource->type) {
@ -1740,8 +1742,8 @@ void genDudeTransform(spritetype* pSprite) {
pXSprite->data1 = pXIncarnation->data1; pXSprite->data1 = pXIncarnation->data1;
pXSprite->data2 = pXIncarnation->data2; pXSprite->data2 = pXIncarnation->data2;
pXSprite->sysData1 = pXIncarnation->data3; pXSprite->sysData1 = pXIncarnation->data3; // soundBase id
pXSprite->sysData2 = pXIncarnation->data4; pXSprite->sysData2 = pXIncarnation->data4; // start hp
pXSprite->dudeGuard = pXIncarnation->dudeGuard; pXSprite->dudeGuard = pXIncarnation->dudeGuard;
pXSprite->dudeDeaf = pXIncarnation->dudeDeaf; pXSprite->dudeDeaf = pXIncarnation->dudeDeaf;
@ -1758,7 +1760,8 @@ void genDudeTransform(spritetype* pSprite) {
pXIncarnation->key = pXIncarnation->dropMsg = 0; pXIncarnation->key = pXIncarnation->dropMsg = 0;
// set hp // 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; int seqId = dudeInfo[pSprite->type - kDudeBase].seqStartID;
switch (pSprite->type) { switch (pSprite->type) {

View file

@ -270,7 +270,9 @@ void Respawn(int nSprite) // 9
pSprite->y = baseSprite[nSprite].y; pSprite->y = baseSprite[nSprite].y;
pSprite->z = baseSprite[nSprite].z; pSprite->z = baseSprite[nSprite].z;
pSprite->cstat |= 0x1101; 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) { switch (pSprite->type) {
default: default:
pSprite->clipdist = getDudeInfo(nType + kDudeBase)->clipdist; pSprite->clipdist = getDudeInfo(nType + kDudeBase)->clipdist;
@ -281,6 +283,12 @@ void Respawn(int nSprite) // 9
seqSpawn(genDudeSeqStartId(pXSprite), 3, pSprite->extra, -1); seqSpawn(genDudeSeqStartId(pXSprite), 3, pSprite->extra, -1);
break; 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); aiInitSprite(pSprite);
pXSprite->key = 0; pXSprite->key = 0;
} else if (pSprite->type == kThingTNTBarrel) { } else if (pSprite->type == kThingTNTBarrel) {

View file

@ -1570,7 +1570,7 @@ DUDEINFO dudeInfo[kDudeMax-kDudeBase] =
256, // angSpeed 256, // angSpeed
// 0, // 0,
7, -1, 18, // nGibType 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, 0, 0, 0, 0, 0,
0, 0,
0 0
@ -1732,20 +1732,4 @@ DUDEINFO gPlayerTemplate[4] =
}; };
DUDEINFO fakeDudeInfo = {}; 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 END_BLD_NS

View file

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

View file

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

View file

@ -328,7 +328,6 @@ void windGenStopWindOnSectors(XSPRITE* pXSource);
int getSpriteMassBySize(spritetype* pSprite); int getSpriteMassBySize(spritetype* pSprite);
bool ceilIsTooLow(spritetype* pSprite); bool ceilIsTooLow(spritetype* pSprite);
void levelEndLevelCustom(int nLevel); void levelEndLevelCustom(int nLevel);
XSPRITE* eventRedirected(int objType, int objXIndex, bool byRx);
bool useCondition(XSPRITE* pXSource, EVENT event); bool useCondition(XSPRITE* pXSource, EVENT event);
bool condPush(XSPRITE* pXSprite, int objType, int objIndex); bool condPush(XSPRITE* pXSprite, int objType, int objIndex);
bool condRestore(XSPRITE* pXSprite); 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 condCheckWall(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS);
bool condCheckSprite(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); 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 #endif
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////

View file

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