- Double print in console fix for consoleSysMsg

- Changes for kModernCondition

# Conflicts:
#	source/blood/src/globals.cpp
This commit is contained in:
NoOneBlood 2020-03-30 22:54:28 +03:00 committed by Christoph Oelckers
parent c27f3b8d20
commit 71b110a75e
3 changed files with 392 additions and 319 deletions

View file

@ -210,6 +210,25 @@ bool nnExtEraseModernStuff(spritetype* pSprite, XSPRITE* pXSprite) {
return erased; return erased;
} }
void nnExtTriggerObject(int objType, int objIndex, int command) {
switch (objType) {
case OBJ_SECTOR:
if (!xsectRangeIsFine(sector[objIndex].extra)) break;
trTriggerSector(objIndex, &xsector[sector[objIndex].extra], command);
break;
case OBJ_WALL:
if (!xwallRangeIsFine(wall[objIndex].extra)) break;
trTriggerWall(objIndex, &xwall[wall[objIndex].extra], command);
break;
case OBJ_SPRITE:
if (!xspriRangeIsFine(sprite[objIndex].extra)) break;
trTriggerSprite(objIndex, &xsprite[sprite[objIndex].extra], command);
break;
}
return;
}
void nnExtResetGlobals() { void nnExtResetGlobals() {
gAllowTrueRandom = gEventRedirectsUsed = false; gAllowTrueRandom = gEventRedirectsUsed = false;
@ -276,8 +295,11 @@ void nnExtInitModernStuff(bool bSaveLoad) {
case kModernCondition: case kModernCondition:
case kModernConditionFalse: case kModernConditionFalse:
if (!bSaveLoad) { if (!bSaveLoad) {
if (!pXSprite->txID || !pXSprite->rxID) if (!pXSprite->rxID) {
ThrowError("\nThe condition must have RX and TX id!\nSPRITE #%d", pSprite->index); ThrowError("\nThe condition must have RX ID!\nSPRITE #%d", pSprite->index);
} else if (!pXSprite->txID && !pSprite->hitag) {
consoleSysMsg("Inactive condition: RX ID %d, SPRITE #%d", pXSprite->rxID, pSprite->index);
}
pSprite->yvel = pSprite->type; // store it here, because inittype gets cleared later. pSprite->yvel = pSprite->type; // store it here, because inittype gets cleared later.
pSprite->type = kModernCondition; pSprite->type = kModernCondition;
@ -391,8 +413,10 @@ void nnExtInitModernStuff(bool bSaveLoad) {
pXSprite->Proximity = true; pXSprite->Proximity = true;
break; break;
case kModernCondition: case kModernCondition:
if (pXSprite->waitTime > 0 && pXSprite->busyTime > 0) if (pXSprite->waitTime > 0 && pXSprite->busyTime > 0) {
ThrowError("\nTracking conditions cannot use waitTime, use busyTime instead!\nRX ID: %d, SPRITE #%d", pXSprite->rxID, pSprite->index); pXSprite->busyTime += ((pXSprite->waitTime * 60) / 10);
consoleSysMsg("Summing busyTime and waitTime for tracking condition #d%, RX ID %d. Result = %d ticks", pSprite->index, pXSprite->rxID, pXSprite->busyTime);
}
pXSprite->Decoupled = false; // must go through operateSprite always pXSprite->Decoupled = false; // must go through operateSprite always
pXSprite->Sight = pXSprite->Impact = pXSprite->Touch = false; pXSprite->Sight = pXSprite->Impact = pXSprite->Touch = false;
@ -400,6 +424,7 @@ void nnExtInitModernStuff(bool bSaveLoad) {
pXSprite->triggerOff = true; pXSprite->triggerOn = false; pXSprite->triggerOff = true; pXSprite->triggerOn = false;
pXSprite->state = pXSprite->restState = 0; pXSprite->state = pXSprite->restState = 0;
pXSprite->targetX = pXSprite->targetY = pXSprite->targetZ = pXSprite->target = -1;
changespritestat(pSprite->index, kStatModernCondition); changespritestat(pSprite->index, kStatModernCondition);
pSprite->cstat |= CSTAT_SPRITE_INVISIBLE; pSprite->cstat |= CSTAT_SPRITE_INVISIBLE;
break; break;
@ -2044,53 +2069,82 @@ void useSeqSpawnerGen(XSPRITE* pXSource, int objType, int index) {
} }
} }
int condSerialize(int objType, int objIndex) {
switch (objType) {
case OBJ_SECTOR: return kCondSerialSector + objIndex;
case OBJ_WALL: return kCondSerialWall + objIndex;
case OBJ_SPRITE: return kCondSerialSprite + objIndex;
}
ThrowError("Unknown object type %d, index %d", objType, objIndex)
return -1;
}
void condUnserialize(int serial, int* objType, int* objIndex) {
if (serial >= kCondSerialSector && serial < kCondSerialWall) {
*objIndex = serial - kCondSerialSector;
*objType = OBJ_SECTOR;
} else if (serial >= kCondSerialWall && serial < kCondSerialSprite) {
*objIndex = serial - kCondSerialWall;
*objType = OBJ_WALL;
} else if (serial >= kCondSerialSprite && serial < kCondSerialMax) {
*objIndex = serial - kCondSerialSprite;
*objType = OBJ_SPRITE;
} else {
ThrowError("%d is not condition serial!");
}
}
bool condPush(XSPRITE* pXSprite, int objType, int objIndex) { bool condPush(XSPRITE* pXSprite, int objType, int objIndex) {
pXSprite->targetX = condSerialize(objType, objIndex);
pXSprite->targetX = objType;
pXSprite->targetY = objIndex;
/*if (objType != pXSprite->targetX || objIndex != pXSprite->targetY) {
int tmp = pXSprite->targetX;
pXSprite->targetX = objType;
pXSprite->dropMsg = tmp;
tmp = pXSprite->targetY;
pXSprite->targetY = objIndex;
pXSprite->targetZ = tmp;
//viewSetSystemMessage("PUSH");
}*/
return true; return true;
} }
bool condRestore(XSPRITE* pXSprite) { bool condRestore(XSPRITE* pXSprite) {
pXSprite->targetX = pXSprite->target; pXSprite->targetX = pXSprite->targetY;
pXSprite->targetY = pXSprite->targetZ;
return true; return true;
} }
bool condCmp(int val, int arg1, int arg2, int arg3) { /*XSPRITE* condGetElse(XSPRITE* pXSprite) {
switch (arg3) { spritetype* pCond = &sprite[pXSprite->reference];
case 0: condCmpr(val, arg1, arg2); for (int i = bucketHead[pXSprite->rxID]; i < bucketHead[pXSprite->rxID + 1]; i++) {
case 1: return (val == arg1); if (rxBucket[i].index == pCond->index) continue;
case 2: return (val >= arg1); else if (rxBucket[i].type == OBJ_SPRITE && xspriRangeIsFine(sprite[rxBucket[i].index].extra)) {
case 3: return (val > arg1); spritetype* pElse = &sprite[rxBucket[i].index];
case 4: return (val <= arg1); if (pElse->type != kModernCondition || pElse->yvel == pCond->yvel)
case 5: return (val < arg1); continue;
case 6: return (val & arg1);
default: XSPRITE* pXElse = &xsprite[pElse->extra];
ThrowError("\nSpecify compare operation!"); if (pXElse->data1 == pXSprite->data1 && pXElse->data2 == pXSprite->data2 && pXElse->data3 == pXSprite->data3
break; && pXElse->data4 == pXSprite->data4) return pXElse;
}
} }
return false; return NULL;
}*/
// normal comparison
bool condCmp(int val, int arg1, int arg2, int comOp) {
if (comOp & 0x2000) return (comOp & CSTAT_SPRITE_BLOCK) ? (val > arg1) : (val >= arg1); // blue sprite
else if (comOp & 0x4000) return (comOp & CSTAT_SPRITE_BLOCK) ? (val < arg1) : (val <= arg1); // green sprite
else return (comOp & CSTAT_SPRITE_BLOCK) ? (val >= arg1 && val <= arg2) : (val == arg1);
} }
bool condCmpr(int val, int min, int max) { // no extra comparison (val always = 0)?
return (max == 0) ? (val == min) : (val >= min && val <= max); bool condCmpne(int arg1, int arg2, int comOp) {
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);
} }
bool condCheckMixed(XSPRITE* pXCond, EVENT event, bool PUSH, bool RVRS) { bool condCheckMixed(XSPRITE* pXCond, EVENT event, int cmpOp, bool PUSH, bool RVRS) {
UNREFERENCED_PARAMETER(PUSH); UNREFERENCED_PARAMETER(PUSH);
UNREFERENCED_PARAMETER(RVRS); UNREFERENCED_PARAMETER(RVRS);
@ -2098,33 +2152,37 @@ bool condCheckMixed(XSPRITE* pXCond, EVENT event, bool PUSH, bool RVRS) {
//int var = -1; //int var = -1;
int cond = pXCond->data1 - kCondMixedBase; int arg1 = pXCond->data2; int cond = pXCond->data1 - kCondMixedBase; int arg1 = pXCond->data2;
int arg2 = pXCond->data3; //int arg3 = pXCond->data4; int arg2 = pXCond->data3; //int arg3 = pXCond->data4;
int objType = pXCond->targetX; int objIndex = pXCond->targetY;
int objType = -1; int objIndex = -1;
condUnserialize(pXCond->targetX, &objType, &objIndex);
switch (cond) { switch (cond) {
case 0: return (objType == OBJ_SECTOR); // is a sector? case 0: return (objType == OBJ_SECTOR && sectRangeIsFine(objIndex)); // is a sector?
case 1: return (objType == OBJ_WALL); // is a wall? case 1: return (objType == OBJ_WALL && wallRangeIsFine(objIndex)); // is a wall?
case 2: return (objType == OBJ_SPRITE); // is a sprite? case 2: return (objType == OBJ_SPRITE && spriRangeIsFine(objIndex)); // is a sprite?
case 10: // index is fine? case 10: // x-index is fine?
case 20: // x-index is fine? case 20: // type in a range?
case 30: // type in a range?
switch (objType) { switch (objType) {
case OBJ_WALL: case OBJ_WALL:
if (cond == 10) return wallRangeIsFine(objIndex); if (cond == 10) return xwallRangeIsFine(wall[objIndex].extra);
else if (cond == 20) return xwallRangeIsFine(wall[objIndex].extra); else return condCmp(wall[objIndex].type, arg1, arg2, cmpOp);
else if (cond == 30) return condCmpr(wall[objIndex].type, arg1, arg2);
break; break;
case OBJ_SPRITE: case OBJ_SPRITE:
if (cond == 10) return spriRangeIsFine(objIndex); if (cond == 10) return xspriRangeIsFine(sprite[objIndex].extra);
else if (cond == 20) return xspriRangeIsFine(sprite[objIndex].extra); else return condCmp((sprite[objIndex].type != kThingBloodChunks) ? sprite[objIndex].type : sprite[objIndex].inittype, arg1, arg2, cmpOp);
else if (cond == 30) return condCmpr((sprite[objIndex].type != kThingBloodChunks) ? sprite[objIndex].type : sprite[objIndex].inittype, arg1, arg2);
break; break;
case OBJ_SECTOR: case OBJ_SECTOR:
if (cond == 10) return sectRangeIsFine(objIndex); if (cond == 10) return xsectRangeIsFine(sector[objIndex].extra);
else if (cond == 20) return xsectRangeIsFine(sector[objIndex].extra); else return condCmp(sector[objIndex].type, arg1, arg2, cmpOp);
else if (cond == 30) return condCmpr(sector[objIndex].type, arg1, arg2);
break; break;
} }
break; break;
case 41:
case 42:
case 43:
case 44:
// 45
// 46
case 50: case 50:
case 51: case 51:
case 52: case 52:
@ -2136,116 +2194,133 @@ bool condCheckMixed(XSPRITE* pXCond, EVENT event, bool PUSH, bool RVRS) {
switch (objType) { switch (objType) {
case OBJ_WALL: { case OBJ_WALL: {
XWALL* pXObj = (xwallRangeIsFine(wall[objIndex].extra)) ? &xwall[wall[objIndex].extra] : NULL; XWALL* pXObj = (xwallRangeIsFine(wall[objIndex].extra)) ? &xwall[wall[objIndex].extra] : NULL;
if (cond == 50) return (pXObj) ? condCmpr(pXObj->rxID, arg1, arg2) : (!arg1 && !arg2); if (cond == 41) return (pXObj) ? condCmp(pXObj->data, arg1, arg2, cmpOp) : condCmpne(arg1, arg2, cmpOp);
else if (cond == 51) return (pXObj) ? condCmpr(pXObj->txID, arg1, arg2) : (!arg1 && !arg2); else if (cond == 50) return (pXObj) ? condCmp(pXObj->rxID, arg1, arg2, cmpOp) : condCmpne(arg1, arg2, cmpOp);
else if (cond == 51) return (pXObj) ? condCmp(pXObj->txID, arg1, arg2, cmpOp) : condCmpne(arg1, arg2, cmpOp);
else if (cond == 52) return (pXObj) ? pXObj->locked : true; else if (cond == 52) return (pXObj) ? pXObj->locked : true;
else if (!pXObj) return false; else if (!pXObj) return false;
else if (cond == 53) return pXObj->triggerOn; else if (cond == 53) return pXObj->triggerOn;
else if (cond == 54) return pXObj->triggerOff; else if (cond == 54) return pXObj->triggerOff;
else if (cond == 55) return pXObj->isTriggered; else if (cond == 55) return pXObj->isTriggered;
else if (cond == 56) return pXObj->state; else if (cond == 56) return pXObj->state;
else if (cond == 57) return pXObj->busy; else if (cond == 57) return condCmp((100 * pXObj->busy) / 65536, arg1, arg2, cmpOp);
else if (cond == 58) return pXObj->dudeLockout; else if (cond == 58) return pXObj->dudeLockout;
break; break;
} }
case OBJ_SPRITE: { case OBJ_SPRITE: {
XSPRITE* pXObj = (xspriRangeIsFine(sprite[objIndex].extra)) ? &xsprite[sprite[objIndex].extra] : NULL; XSPRITE* pXObj = (xspriRangeIsFine(sprite[objIndex].extra)) ? &xsprite[sprite[objIndex].extra] : NULL;
if (cond == 50) return (pXObj) ? condCmpr(pXObj->rxID, arg1, arg2) : (!arg1 && !arg2); if (cond >= 41 && cond <= 44)
else if (cond == 51) return (pXObj) ? condCmpr(pXObj->txID, arg1, arg2) : (!arg1 && !arg2); return (pXObj) ? condCmp(getDataFieldOfObject(OBJ_SPRITE, objIndex, (cond - 41) + 1), arg1, arg2, cmpOp) : condCmpne(arg1, arg2, cmpOp);
else if (cond == 50) return (pXObj) ? condCmp(pXObj->rxID, arg1, arg2, cmpOp) : condCmpne(arg1, arg2, cmpOp);
else if (cond == 51) return (pXObj) ? condCmp(pXObj->txID, arg1, arg2, cmpOp) : condCmpne(arg1, arg2, cmpOp);
else if (cond == 52) return (pXObj) ? pXObj->locked : true; else if (cond == 52) return (pXObj) ? pXObj->locked : true;
else if (!pXObj) return false; else if (!pXObj) return false;
else if (cond == 53) return pXObj->triggerOn; else if (cond == 53) return pXObj->triggerOn;
else if (cond == 54) return pXObj->triggerOff; else if (cond == 54) return pXObj->triggerOff;
else if (cond == 55) return pXObj->isTriggered; else if (cond == 55) return pXObj->isTriggered;
else if (cond == 56) return pXObj->state; else if (cond == 56) return pXObj->state;
else if (cond == 57) return pXObj->busy; else if (cond == 57) return condCmp((100 * pXObj->busy) / 65536, arg1, arg2, cmpOp);
else if (cond == 58) return pXObj->DudeLockout; else if (cond == 58) return pXObj->DudeLockout;
break; break;
} }
case OBJ_SECTOR: { case OBJ_SECTOR: {
XSECTOR* pXObj = (xsectRangeIsFine(sector[objIndex].extra)) ? &xsector[sector[objIndex].extra] : NULL; XSECTOR* pXObj = (xsectRangeIsFine(sector[objIndex].extra)) ? &xsector[sector[objIndex].extra] : NULL;
if (cond == 50) return (pXObj) ? condCmpr(pXObj->rxID, arg1, arg2) : (!arg1 && !arg2); if (cond == 41) return (pXObj) ? condCmp(pXObj->data, arg1, arg2, cmpOp) : condCmpne(arg1, arg2, cmpOp);
else if (cond == 51) return (pXObj) ? condCmpr(pXObj->txID, arg1, arg2) : (!arg1 && !arg2); if (cond == 50) return (pXObj) ? condCmp(pXObj->rxID, arg1, arg2, cmpOp) : condCmpne(arg1, arg2, cmpOp);
else if (cond == 51) return (pXObj) ? condCmp(pXObj->txID, arg1, arg2, cmpOp) : condCmpne(arg1, arg2, cmpOp);
else if (cond == 52) return (pXObj) ? pXObj->locked : true; else if (cond == 52) return (pXObj) ? pXObj->locked : true;
else if (!pXObj) return false; else if (!pXObj) return false;
else if (cond == 53) return pXObj->triggerOn; else if (cond == 53) return pXObj->triggerOn;
else if (cond == 54) return pXObj->triggerOff; else if (cond == 54) return pXObj->triggerOff;
else if (cond == 55) return pXObj->isTriggered; else if (cond == 55) return pXObj->isTriggered;
else if (cond == 56) return pXObj->state; else if (cond == 56) return pXObj->state;
else if (cond == 57) return pXObj->busy; else if (cond == 57) return condCmp((100 * pXObj->busy) / 65536, arg1, arg2, cmpOp);
else if (cond == 58) return pXObj->dudeLockout; else if (cond == 58) return pXObj->dudeLockout;
break; break;
} }
} }
break; break;
case 99: return condCmpr(event.cmd, arg1, arg2); // this codition received specified command? case 99: return condCmp(event.cmd, arg1, arg2, cmpOp); // this codition received specified command?
} }
ThrowError("\nMixed: Unexpected condition id (%d)!", cond); ThrowError("\nMixed: Unexpected condition id (%d)!", cond);
return false; return false;
} }
bool condCheckSector(XSPRITE* pXCond, bool PUSH, bool RVRS) { bool condCheckSector(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS) {
UNREFERENCED_PARAMETER(RVRS); UNREFERENCED_PARAMETER(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 = pXCond->targetX; int objIndex = pXCond->targetY;
int objType = -1; int objIndex = -1;
condUnserialize(pXCond->targetX, &objType, &objIndex);
if (objType != OBJ_SECTOR || !sectRangeIsFine(objIndex)) if (objType != OBJ_SECTOR || !sectRangeIsFine(objIndex))
ThrowError("\nSector conditions:\nObject #%d (objType: %d) is not a sector!", objType, objIndex); ThrowError("\nSector conditions:\nObject #%d (objType: %d) is not a sector!", objIndex, objType);
sectortype* pSect = &sector[objIndex]; sectortype* pSect = &sector[objIndex];
XSECTOR* pXSect = (xsectRangeIsFine(pSect->extra)) ? &xsector[pSect->extra] : NULL; XSECTOR* pXSect = (xsectRangeIsFine(pSect->extra)) ? &xsector[pSect->extra] : NULL;
if (cond < (kCondRange >> 1)) { if (cond < (kCondRange >> 1)) {
switch (cond) { switch (cond) {
default: return false; default: break;
case 0: return condCmpr(pSect->floorpicnum, arg1, arg2); case 0: return condCmp(pSect->floorpicnum, arg1, arg2, cmpOp);
case 1: return condCmpr(pSect->ceilingpicnum, arg1, arg2); case 1: return condCmp(pSect->ceilingpicnum, arg1, arg2, cmpOp);
case 2: return condCmpr((!arg3) ? pSect->floorxpanning : pSect->floorypanning, arg1, arg2); case 2: return condCmp((!arg3) ? pSect->floorxpanning : pSect->floorypanning, arg1, arg2, cmpOp);
case 3: return condCmpr((!arg3) ? pSect->ceilingxpanning : pSect->ceilingypanning, arg1, arg2); case 3: return condCmp((!arg3) ? pSect->ceilingxpanning : pSect->ceilingypanning, arg1, arg2, cmpOp);
case 4: return condCmpr(pSect->floorpal, arg1, arg2); case 4: return condCmp(pSect->floorpal, arg1, arg2, cmpOp);
case 5: return condCmpr(pSect->ceilingpal, arg1, arg2); case 5: return condCmp(pSect->ceilingpal, arg1, arg2, cmpOp);
case 6: return condCmpr(pSect->floorheinum, arg1, arg2); case 6: return condCmp(pSect->floorheinum, arg1, arg2, cmpOp);
case 7: return condCmpr(pSect->ceilingheinum, arg1, arg2); case 7: return condCmp(pSect->ceilingheinum, arg1, arg2, cmpOp);
case 8: return condCmpr(pSect->floorshade, arg1, arg2); case 8: return condCmp(pSect->floorshade, arg1, arg2, cmpOp);
case 9: return condCmpr(pSect->ceilingshade, arg1, arg2); case 9: return condCmp(pSect->ceilingshade, arg1, arg2, cmpOp);
case 10: return (pSect->floorstat & arg1); case 10: return (pSect->floorstat & arg1);
case 11: return (pSect->ceilingstat & arg1); case 11: return (pSect->ceilingstat & arg1);
case 25: return (pSect->hitag & arg1); case 25: return (pSect->hitag & arg1);
case 26: return condCmpr(pSect->wallnum, arg1, arg2); case 27: return condCmp(pSect->visibility, arg1, arg2, cmpOp);
case 27: return condCmpr(pSect->visibility, arg1, arg2);
case 28: return condCmpr(pSect->fogpal, arg1, arg2);
case 29:
if (!condCmpr(pSect->wallptr, arg1, arg2)) return false;
else if (PUSH) condPush(pXCond, OBJ_WALL, pSect->wallptr);
return true;
case 30: // required sprite type is in current sector? case 30: // required sprite type is in current sector?
for (var = headspritesect[objIndex]; var >= 0; var = nextspritesect[var]) { for (var = headspritesect[objIndex]; var >= 0; var = nextspritesect[var]) {
if (condCmpr(sprite[var].type, arg1, arg2)) { if (!condCmp(sprite[var].type, arg1, arg2, cmpOp)) continue;
if (PUSH) condPush(pXCond, OBJ_SPRITE, var); else if (PUSH) condPush(pXCond, OBJ_SPRITE, var);
return true; return true;
} }
}
return false; return false;
} }
} else if (pXSect) { } else if (pXSect) {
switch (cond) { switch (cond) {
default: return false; default: break;
case 50: return pXSect->Underwater; case 50: return pXSect->Underwater;
case 51: return condCmpr(pXSect->data, arg1, arg2); case 60: // compare floor height (in %)
// 52 case 61: { // compare ceil height (in %)
// 53 int h = 0; int curH = 0;
// 54 switch (pSect->type) {
case kSectorZMotion:
case kSectorRotate:
case kSectorSlide:
if (cond == 60) {
h = ClipLow(abs(pXSect->onFloorZ - pXSect->offFloorZ), 1);
curH = abs(pSect->floorz - pXSect->offFloorZ);
} else {
h = ClipLow(abs(pXSect->onCeilZ - pXSect->offCeilZ), 1);
curH = abs(pSect->ceilingz - pXSect->offCeilZ);
}
return condCmp((100 * curH) / h, arg1, arg2, cmpOp);
default:
ThrowError("\nSector conditions:\nUsupported sector type %d", pSect->type);
return false;
}
}
} }
} else { } else {
switch (cond) { switch (cond) {
default: return false; default: return false;
case 51: case 60:
return (!arg1 && !arg2); case 61:
return condCmpne(arg1, arg2, cmpOp);
} }
} }
@ -2253,113 +2328,104 @@ bool condCheckSector(XSPRITE* pXCond, bool PUSH, bool RVRS) {
return false; return false;
} }
bool condCheckWall(XSPRITE* pXCond, bool PUSH, bool RVRS) { bool condCheckWall(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS) {
UNREFERENCED_PARAMETER(RVRS); UNREFERENCED_PARAMETER(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 = pXCond->targetX; int objIndex = pXCond->targetY;
int objType = -1; int objIndex = -1;
condUnserialize(pXCond->targetX, &objType, &objIndex);
if (objType != OBJ_WALL || !wallRangeIsFine(objIndex)) if (objType != OBJ_WALL || !wallRangeIsFine(objIndex))
ThrowError("\nWall conditions:\nObject #%d (objType: %d) is not a wall!", objType, objIndex); 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) {
default: return false; default: break;
case 0: return condCmpr(pWall->picnum, arg1, arg2); case 0: return condCmp(pWall->picnum, arg1, arg2, cmpOp);
case 1: return condCmpr(pWall->overpicnum, arg1, arg2); case 1: return condCmp(pWall->overpicnum, arg1, arg2, cmpOp);
case 2: return condCmpr((!arg3) ? pWall->xrepeat : pWall->xpanning, arg1, arg2); case 2: return condCmp((!arg3) ? pWall->xrepeat : pWall->xpanning, arg1, arg2, cmpOp);
case 3: return condCmpr((!arg3) ? pWall->yrepeat : pWall->ypanning, arg1, arg2); case 3: return condCmp((!arg3) ? pWall->yrepeat : pWall->ypanning, arg1, arg2, cmpOp);
case 4: return condCmpr(pWall->pal, arg1, arg2); case 4: return condCmp(pWall->pal, arg1, arg2, cmpOp);
case 5: case 5:
if (!condCmpr(pWall->nextwall, arg1, arg2)) return false; if (!wallRangeIsFine(pWall->nextwall)) return false;
else if (PUSH) condPush(pXCond, OBJ_WALL, pWall->nextwall); else if (PUSH) condPush(pXCond, OBJ_WALL, pWall->nextwall);
return true; return true;
case 6: return (pWall->hitag & arg1); case 6: return (pWall->hitag & arg1);
case 7: return (pWall->cstat & arg1); case 7: return (pWall->cstat & arg1);
case 9: return condCmpr(pWall->shade, arg1, arg2); case 9: return condCmp(pWall->shade, arg1, arg2, cmpOp);
case 10: case 10:
if (!condCmpr(pWall->nextsector, arg1, arg2)) return false; if (!sectRangeIsFine(pWall->nextsector)) return false;
else if (PUSH) condPush(pXCond, OBJ_SECTOR, pWall->nextsector); else if (PUSH) condPush(pXCond, OBJ_SECTOR, pWall->nextsector);
return true; return true;
case 11: case 11:
if (!condCmpr((var = sectorofwall(objIndex)), arg1, arg2)) return false; if (!sectRangeIsFine((var = sectorofwall(objIndex)))) return false;
else if (PUSH) condPush(pXCond, OBJ_SECTOR, var); else if (PUSH) condPush(pXCond, OBJ_SECTOR, var);
return true; return true;
case 12: // this wall is a mirror? // must be as constants here case 12: // this wall is a mirror? // must be as constants here
return (pWall->type != kWallStack && condCmpr(pWall->picnum, 4080, (4080 + 16) - 1)); return (pWall->type != kWallStack && condCmp(pWall->picnum, 4080, (4080 + 16) - 1, 0));
case 13: // next wall belongs to sector? case 13: // next wall belongs to sector?
if (!sectRangeIsFine(var = sectorofwall(pWall->nextwall))) return false; if (!sectRangeIsFine(var = sectorofwall(pWall->nextwall))) return false;
else if (PUSH) condPush(pXCond, OBJ_SECTOR, var); else if (PUSH) condPush(pXCond, OBJ_SECTOR, var);
return true; return true;
} }
} else if (pXWall) {
switch (cond) {
default: return false;
case 51: return condCmpr(pXWall->data, arg1, arg2);
// 52
// 53
// 54
}
} else {
switch (cond) {
default: return false;
case 51:
return (!arg1 && !arg2);
}
} }
ThrowError("\nWall conditions: Unexpected condition id (%d)!", cond); ThrowError("\nWall conditions: Unexpected condition id (%d)!", cond);
return false; return false;
} }
bool condCheckDude(XSPRITE* pXCond, bool PUSH, bool RVRS) { bool condCheckDude(XSPRITE* pXCond, int cmpOp, bool PUSH, bool 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;
int objType = pXCond->targetX; int objIndex = pXCond->targetY;
if (objType != OBJ_SPRITE || !spriRangeIsFine(objIndex)) int objType = -1; int objIndex = -1;
ThrowError("\nDude conditions:\nObject #%d (objType: %d) is not a dude!", objType, objIndex); condUnserialize(pXCond->targetX, &objType, &objIndex);
spritetype* pSpr = &sprite[objIndex]; XSPRITE* pXSpr = NULL; if (objType != OBJ_SPRITE || !spriRangeIsFine(objIndex) || !xspriRangeIsFine(sprite[objIndex].extra))
if (xspriRangeIsFine(pSpr->extra)) pXSpr = &xsprite[pSpr->extra]; ThrowError("\nDude conditions:\nObject #%d (objType: %d) is not a dude!", objIndex, objType);
else ThrowError("\nDude conditions:\nObject #%d (objType: %d) is not a dude! (extra out of range)", objType, objIndex);
spritetype* pSpr = &sprite[objIndex]; XSPRITE* pXSpr = &xsprite[pSpr->extra];
if (pXSpr->health <= 0 || pSpr->type == kThingBloodChunks) return false; if (pXSpr->health <= 0 || pSpr->type == kThingBloodChunks) return false;
else if (cond < (kCondRange >> 1)) { else if (cond < (kCondRange >> 1)) {
if ((pPlayer = getPlayerById(pSpr->type)) == NULL) if ((pPlayer = getPlayerById(pSpr->type)) == NULL)
ThrowError("\nDude conditions:\nObject #%d (objType: %d) is not a player!", objType, objIndex); ThrowError("\nDude conditions:\nObject #%d (objType: %d) is not a player!", objIndex, objType);
pSpr = pPlayer->pSprite; pXSpr = pPlayer->pXSprite; pSpr = pPlayer->pSprite; pXSpr = pPlayer->pXSprite;
switch (cond) { switch (cond) {
default: break; default: break;
case 0: return (pPlayer->lifeMode == arg1); case 0: return condCmp(pPlayer->lifeMode, arg1, arg2, cmpOp);
case 1: return (pPlayer->posture == arg1); case 1: return condCmp(pPlayer->posture, arg1, arg2, cmpOp);
case 2: return (arg1 > 0 && arg1 < 8 && pPlayer->hasKey[arg1 - 1]); case 2: return (arg1 >= 0 && arg1 < 7 && pPlayer->hasKey[arg1]);
case 3: return (arg1 > 0 && arg1 < 15 && pPlayer->hasWeapon[arg1 - 1]); case 3: return (arg1 >= 0 && arg1 < 14 && pPlayer->hasWeapon[arg1]);
case 4: return (pPlayer->curWeapon == arg1); case 4: return condCmp(pPlayer->curWeapon, arg1, arg2, cmpOp);
case 5: return (arg1 > 0 && arg1 < 6 && pPlayer->packSlots[arg1 - 1].curAmount > 0); case 5: return (arg1 >= 0 && arg1 < 5 && condCmp(pPlayer->packSlots[arg1].curAmount, arg2, arg3, cmpOp));
case 6: return (arg1 > 0 && arg1 < 6 && pPlayer->packSlots[arg1 - 1].isActive); case 6: return (arg1 >= 0 && arg1 < 5 && pPlayer->packSlots[arg1].isActive);
case 7: return (pPlayer->packItemId == arg1); case 7: return condCmp(pPlayer->packItemId, arg1, arg2, cmpOp);
// 8 case 8: // check for powerup amount in %
if (arg1 >= 0 && arg1 < 29) var = 12 + arg1; // allowable powerups
else ThrowError("Unexpected powerup #%d", arg1);
return condCmp((100 * pPlayer->pwUpTime[var]) / gPowerUpInfo[var].bonusTime, arg2, arg3, cmpOp);
// 9 // 9
case 10: // check keys pressed case 10: // check keys pressed
switch (arg1) { switch (arg1) {
case 1: return (pPlayer->input.forward > 0); // forward case 0: return (pPlayer->input.forward > 0); // forward
case 2: return (pPlayer->input.forward < 0); // backward case 1: return (pPlayer->input.forward < 0); // backward
case 3: return (pPlayer->input.strafe > 0); // left case 2: return (pPlayer->input.strafe > 0); // left
case 4: return (pPlayer->input.strafe < 0); // right case 3: return (pPlayer->input.strafe < 0); // right
case 5: return (pPlayer->input.buttonFlags.jump); // jump case 4: return (pPlayer->input.buttonFlags.jump); // jump
case 6: return (pPlayer->input.buttonFlags.crouch); // crouch case 5: return (pPlayer->input.buttonFlags.crouch); // crouch
case 7: return (pPlayer->input.buttonFlags.shoot); // normal fire weapon case 6: return (pPlayer->input.buttonFlags.shoot); // normal fire weapon
case 8: return (pPlayer->input.buttonFlags.shoot2); // alt fire weapon case 7: return (pPlayer->input.buttonFlags.shoot2); // alt fire weapon
default: default:
ThrowError("\nDude conditions:\nSpecify a key!"); ThrowError("\nDude conditions:\nSpecify a key!");
break; break;
@ -2368,13 +2434,13 @@ bool condCheckDude(XSPRITE* pXCond, bool PUSH, bool RVRS) {
case 11: return (pPlayer->isRunning); case 11: return (pPlayer->isRunning);
case 12: return (pPlayer->fallScream); // falling in abyss? case 12: return (pPlayer->fallScream); // falling in abyss?
// ...... // ......
case 46: return condCmpr(pPlayer->sceneQav >= 0, arg1, arg2); case 46: return condCmp(pPlayer->sceneQav, arg1, arg2, cmpOp);
case 47: return pPlayer->godMode; case 47: return pPlayer->godMode;
case 48: return isShrinked(pSpr); case 48: return isShrinked(pSpr);
case 49: return isGrown(pSpr); case 49: return isGrown(pSpr);
} }
} else if (IsDudeSprite(pSpr)) { } else if (IsDudeSprite(pSpr) && !IsPlayerSprite(pSpr)) {
switch (cond) { switch (cond) {
default: break; default: break;
case 50: // dude have any targets? case 50: // dude have any targets?
@ -2385,7 +2451,7 @@ bool condCheckDude(XSPRITE* pXCond, bool PUSH, bool RVRS) {
} }
} else { } else {
ThrowError("\nDude conditions:\nObject #%d (objType: %d) is not an enemy!", objType, objIndex); ThrowError("\nDude conditions:\nObject #%d (objType: %d) is not an enemy!", objIndex, objType);
} }
@ -2393,47 +2459,50 @@ bool condCheckDude(XSPRITE* pXCond, bool PUSH, bool RVRS) {
return false; return false;
} }
bool condCheckSprite(XSPRITE* pXCond, bool PUSH, bool RVRS) { bool condCheckSprite(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS) {
int var = -1; PLAYER* pPlayer = NULL; 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;
int objType = pXCond->targetX; int objIndex = pXCond->targetY;
int objType = -1; int objIndex = -1;
condUnserialize(pXCond->targetX, &objType, &objIndex);
if (objType != OBJ_SPRITE || !spriRangeIsFine(objIndex)) if (objType != OBJ_SPRITE || !spriRangeIsFine(objIndex))
ThrowError("\nSprite conditions:\nObject #%d (objType: %d) is not a sprite!", objType, objIndex); ThrowError("\nSprite condition %d:\nObject #%d (objType: %d) is not a sprite!", cond, objIndex, objType);
spritetype* pSpr = &sprite[objIndex]; spritetype* pSpr = &sprite[objIndex];
XSPRITE* pXSpr = (xspriRangeIsFine(pSpr->extra)) ? &xsprite[pSpr->extra] : NULL; XSPRITE* pXSpr = (xspriRangeIsFine(pSpr->extra)) ? &xsprite[pSpr->extra] : NULL;
if (cond < (kCondRange >> 1)) { if (cond < (kCondRange >> 1)) {
switch (cond) { switch (cond) {
default: return false; default: break;
case 0: return condCmpr(pSpr->picnum, arg1, arg2); case 0: return condCmp(pSpr->picnum, arg1, arg2, cmpOp);
case 1: return condCmpr(pSpr->statnum, arg1, arg2); case 1: return condCmp(pSpr->statnum, arg1, arg2, cmpOp);
case 2: return condCmpr(pSpr->xrepeat, arg1, arg2); case 2: return condCmp((!arg3) ? pSpr->xrepeat : pSpr->xoffset, arg1, arg2, cmpOp);
case 3: return condCmpr(pSpr->yrepeat, arg1, arg2); case 3: return condCmp((!arg3) ? pSpr->yrepeat : pSpr->yoffset, arg1, arg2, cmpOp);
case 4: return condCmpr(pSpr->pal, arg1, arg2); case 4: return condCmp(pSpr->pal, arg1, arg2, cmpOp);
case 5: return condCmpr((pSpr->ang & 2047), arg1, arg2); case 5: return condCmp((pSpr->ang & 2047), arg1, arg2, cmpOp);
case 6: return (pSpr->flags & arg1); case 6: return (pSpr->flags & arg1);
case 7: return (pSpr->cstat & arg1); case 7: return (pSpr->cstat & arg1);
case 8: case 8:
if (!spriRangeIsFine(pSpr->owner)) return false; if (!spriRangeIsFine(pSpr->owner)) return false;
else if (PUSH) condPush(pXCond, OBJ_SPRITE, pSpr->owner); else if (PUSH) condPush(pXCond, OBJ_SPRITE, pSpr->owner);
return true; return true;
case 9: return condCmpr(pSpr->shade, arg1, arg2); case 9: return condCmp(pSpr->shade, arg1, arg2, cmpOp);
case 10: // stays in a sector? case 10: // stays in a sector?
if (!sectRangeIsFine(pSpr->sectnum)) return false; if (!sectRangeIsFine(pSpr->sectnum)) return false;
else if (PUSH) condPush(pXCond, OBJ_SECTOR, pSpr->sectnum); else if (PUSH) condPush(pXCond, OBJ_SECTOR, pSpr->sectnum);
return true; return true;
case 11: return condCmpr(pSpr->clipdist, arg1, arg2); case 11: return condCmp(pSpr->clipdist, arg1, arg2, cmpOp);
case 12: return (xvel[pSpr->index] || yvel[pSpr->index] || zvel[pSpr->index]); case 12:
case 13: return (xvel[pSpr->index]); switch (arg1) {
case 14: return (yvel[pSpr->index]); default: return (xvel[pSpr->index] || yvel[pSpr->index] || zvel[pSpr->index]);
case 15: return (zvel[pSpr->index]); case 1: return (xvel[pSpr->index]);
// 16 case 2: return (yvel[pSpr->index]);
// 17 case 3: return (zvel[pSpr->index]);
// 18 }
break;
case 19: case 19:
if (!spriteIsUnderwater(pSpr) && !spriteIsUnderwater(pSpr, true)) return false; if (!spriteIsUnderwater(pSpr) && !spriteIsUnderwater(pSpr, true)) return false;
else if (PUSH) condPush(pXCond, OBJ_SECTOR, pSpr->sectnum); else if (PUSH) condPush(pXCond, OBJ_SECTOR, pSpr->sectnum);
@ -2452,70 +2521,51 @@ bool condCheckSprite(XSPRITE* pXCond, bool PUSH, bool RVRS) {
var = HitScan(pSpr, pPlayer->zWeapon - pSpr->z, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, arg1, arg3 << 1); var = HitScan(pSpr, pPlayer->zWeapon - pSpr->z, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, arg1, arg3 << 1);
else if (IsDudeSprite(pSpr)) else if (IsDudeSprite(pSpr))
var = HitScan(pSpr, pSpr->z, Cos(pSpr->ang) >> 16, Sin(pSpr->ang) >> 16, gDudeSlope[pSpr->extra], arg1, arg3 << 1); var = HitScan(pSpr, pSpr->z, Cos(pSpr->ang) >> 16, Sin(pSpr->ang) >> 16, gDudeSlope[pSpr->extra], arg1, arg3 << 1);
else if ((cond == 34 || cond == 35) && !RVRS)
var = HitScan(pSpr, pSpr->z, 1, 1, ((cond == 34) ? -0x4000 : 0x4000), arg1, arg3 << 1);
else else
var = HitScan(pSpr, pSpr->z, Cos(pSpr->ang) >> 16, Sin(pSpr->ang) >> 16, 0, arg1, arg3 << 1); var = HitScan(pSpr, pSpr->z, Cos(pSpr->ang) >> 16, Sin(pSpr->ang) >> 16, 0, arg1, arg3 << 1);
if (var >= 0) {
switch (cond) { switch (cond) {
case 34: case 34: retn = (var == 1); break;
if (var != 1) return false; case 35: retn = (var == 2); break;
else if (PUSH) condPush(pXCond, OBJ_SECTOR, gHitInfo.hitsect); case 36: retn = (var == 0 || var == 4); break;
return true; case 37: retn = (var == 3); break;
case 35:
if (var != 2) return false;
else if (PUSH) condPush(pXCond, OBJ_SECTOR, gHitInfo.hitsect);
return true;
case 36:
if (var != 0 && var != 4) return false;
else if (PUSH) condPush(pXCond, OBJ_WALL, gHitInfo.hitwall);
return true;
case 37:
if (var != 3) return false;
else if (PUSH) condPush(pXCond, OBJ_SPRITE, gHitInfo.hitsprite);
return true;
} }
return false;
case 38: // check for proximity
arg3 = ClipRange(arg3, 48, 512);
for (int i = 0, num = 0; i < kMaxSprites; i++) {
if (sprite[i].statnum == kStatFree || (sprite[i].flags & kHitagFree) || !condCmpr(sprite[i].type, arg1, arg2)) continue;
else if (num++ > Numsprites) break;
int oX = klabs(pSpr->x - sprite[i].x) >> 4; if (PUSH) {
if (oX > arg3) continue; switch (var) {
case 3:
int oY = klabs(pSpr->y - sprite[i].y) >> 4; condPush(pXCond, OBJ_SPRITE, gHitInfo.hitsprite);
if (oY > arg3) continue; break;
case 0: case 4:
int oZ = klabs(pSpr->z - sprite[i].z) >> 8; condPush(pXCond, OBJ_WALL, gHitInfo.hitwall);
if (oZ > arg3) continue; break;
case 1: case 2:
if (approxDist(oX, oY) > arg3) continue; condPush(pXCond, OBJ_SECTOR, gHitInfo.hitsect);
else if (PUSH) condPush(pXCond, OBJ_SPRITE, i); break;
return true;
} }
return false; }
}
return retn;
} }
} else if (pXSpr) { } else if (pXSpr) {
switch (cond) { switch (cond) {
default: return false; default: break;
case 50: return ((!arg1 && !arg2 && pSpr->type == kThingBloodChunks) ? true : condCmpr(pXSpr->health, arg1, arg2)); case 50: // compare hp (in %)
case 51: return condCmpr(pXSpr->data1, arg1, arg2); if (IsDudeSprite(pSpr)) var = ((pXSpr->data4 <= 0) ? getDudeInfo(pSpr->type)->startHealth : pXSpr->data4) << 4;
case 52: return condCmpr(pXSpr->data2, arg1, arg2); else if (condCmpne(arg1, arg2, cmpOp) && pSpr->type == kThingBloodChunks) return true;
case 53: return condCmpr(pXSpr->data3, arg1, arg2); else if (pSpr->type >= kThingBase && pSpr->type < kThingMax)
case 54: return condCmpr(pXSpr->data4, arg1, arg2); var = thingInfo[pSpr->type - kThingBase].startHealth << 4;
// 55
// 56 return condCmp((100 * pXSpr->health) / ClipLow(var, 1), arg1, arg2, cmpOp);
// 57 case 70: // touching ceil of sector?
case 70: // touching floor of sector?
if ((gSpriteHit[pSpr->extra].florhit & 0xc000) != 0x4000) return false;
else if (PUSH) condPush(pXCond, OBJ_SECTOR, gSpriteHit[pSpr->extra].florhit & 0x3fff);
return true;
case 71: // touching ceil of sector?
if ((gSpriteHit[pSpr->extra].ceilhit & 0xc000) != 0x4000) return false; if ((gSpriteHit[pSpr->extra].ceilhit & 0xc000) != 0x4000) return false;
else if (PUSH) condPush(pXCond, OBJ_SECTOR, gSpriteHit[pSpr->extra].ceilhit & 0x3fff); else if (PUSH) condPush(pXCond, OBJ_SECTOR, gSpriteHit[pSpr->extra].ceilhit & 0x3fff);
return true; return true;
case 71: // touching floor of sector?
if ((gSpriteHit[pSpr->extra].florhit & 0xc000) != 0x4000) return false;
else if (PUSH) condPush(pXCond, OBJ_SECTOR, gSpriteHit[pSpr->extra].florhit & 0x3fff);
return true;
case 72: // touching walls of sector? case 72: // touching walls of sector?
if ((gSpriteHit[pSpr->extra].hit & 0xc000) != 0x8000) return false; if ((gSpriteHit[pSpr->extra].hit & 0xc000) != 0x8000) return false;
else if (PUSH) condPush(pXCond, OBJ_WALL, gSpriteHit[pSpr->extra].hit & 0x3fff); else if (PUSH) condPush(pXCond, OBJ_WALL, gSpriteHit[pSpr->extra].hit & 0x3fff);
@ -2535,52 +2585,24 @@ bool condCheckSprite(XSPRITE* pXCond, bool PUSH, bool RVRS) {
if ((gSpriteHit[pSpr->extra].ceilhit & 0xc000) == 0xc000) var = gSpriteHit[pSpr->extra].ceilhit & 0x3fff; if ((gSpriteHit[pSpr->extra].ceilhit & 0xc000) == 0xc000) var = gSpriteHit[pSpr->extra].ceilhit & 0x3fff;
break; break;
} }
if (var < 0) { if (var < 0) return false;
// check if some sprite touching current else if (PUSH) condPush(pXCond, OBJ_SPRITE, var);
for (int i = headspritestat[kStatDude]; i >= 0; i = nextspritestat[i]) {
if (!spriRangeIsFine(xsprite[i].reference)) continue;
int extra = sprite[xsprite[i].reference].extra;
switch (arg3) {
case 0:
case 3:
if ((gSpriteHit[extra].florhit & 0xc000) == 0xc000) var = gSpriteHit[extra].florhit & 0x3fff;
if (arg3 || var >= 0) break;
fallthrough__;
case 2:
if ((gSpriteHit[extra].hit & 0xc000) == 0xc000) var = gSpriteHit[extra].hit & 0x3fff;
if (arg3 || var >= 0) break;
fallthrough__;
case 1:
if ((gSpriteHit[extra].ceilhit & 0xc000) == 0xc000) var = gSpriteHit[extra].ceilhit & 0x3fff;
break;
}
if (var == pSpr->index)
break;
}
}
if (var >= 0) {
if (PUSH) condPush(pXCond, OBJ_SPRITE, var);
return true; return true;
} case 76: // compare burn time (in %)
return false; var = (IsDudeSprite(pSpr)) ? 2400 : 1200;
case 76: // sprite is set on fire? if (!condCmp((100 * pXSpr->burnTime) / var, arg1, arg2, cmpOp)) return false;
if (!condCmpr(pXSpr->burnTime, arg1, arg2)) return false;
else if (PUSH) condPush(pXCond, OBJ_SPRITE, pXSpr->burnSource); else if (PUSH) condPush(pXCond, OBJ_SPRITE, pXSpr->burnSource);
return true; return true;
case 79: case 79:
return condCmpr(getSpriteMassBySize(pSpr), arg1, arg2); // mass of the sprite in a range? return condCmp(getSpriteMassBySize(pSpr), arg1, arg2, cmpOp); // mass of the sprite in a range?
} }
} else { } else {
switch (cond) { switch (cond) {
default: return false; default: return false;
case 50: case 50:
case 51:
case 52:
case 53:
case 54:
case 76: case 76:
return (!arg1 && !arg2); case 79:
return condCmpne(arg1, arg2, cmpOp);
} }
} }
@ -2935,6 +2957,7 @@ void aiFightFreeAllTargets(XSPRITE* pXSource) {
return; return;
} }
bool aiFightDudeIsAffected(XSPRITE* pXDude) { bool aiFightDudeIsAffected(XSPRITE* pXDude) {
if (pXDude->rxID <= 0 || pXDude->locked == 1) return false; if (pXDude->rxID <= 0 || pXDude->locked == 1) return false;
for (int nSprite = headspritestat[kStatModernDudeTargetChanger]; nSprite >= 0; nSprite = nextspritestat[nSprite]) { for (int nSprite = headspritestat[kStatModernDudeTargetChanger]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
@ -3055,6 +3078,29 @@ int aiFightGetFineTargetDist(spritetype* pSprite, spritetype* pTarget) {
bool modernTypeOperateSprite(int nSprite, spritetype* pSprite, XSPRITE* pXSprite, EVENT event) { bool modernTypeOperateSprite(int nSprite, spritetype* pSprite, XSPRITE* pXSprite, EVENT event) {
if (event.cmd >= kCmdLock && event.cmd <= kCmdToggleLock) {
switch (event.cmd) {
case kCmdLock:
pXSprite->locked = 1;
return true;
case kCmdUnlock:
pXSprite->locked = 0;
break;
case kCmdToggleLock:
pXSprite->locked = pXSprite->locked ^ 1;
break;
}
if (!pXSprite->locked) {
switch (pSprite->type) {
case kModernCondition:
if (pXSprite->busyTime > 0) evPost(pSprite->index, OBJ_SPRITE, 0, kCallbackCondition);
break;
}
}
return true;
}
if (pSprite->statnum == kStatDude && IsDudeSprite(pSprite)) { if (pSprite->statnum == kStatDude && IsDudeSprite(pSprite)) {
switch (event.cmd) { switch (event.cmd) {
@ -3690,28 +3736,28 @@ void useSequentialTx(XSPRITE* pXSource, COMMAND_ID cmd, bool setState) {
//evSend(pSource->index, OBJ_SPRITE, pXSource->txID, (COMMAND_ID)pXSource->command); //evSend(pSource->index, OBJ_SPRITE, pXSource->txID, (COMMAND_ID)pXSource->command);
} }
void useCondition(XSPRITE* pXSource, EVENT event) { bool useCondition(XSPRITE* pXSource, EVENT event) {
spritetype* pSource = &sprite[pXSource->reference]; spritetype* pSource = &sprite[pXSource->reference];
int objType = event.type; int objIndex = event.index; int objType = event.type; int objIndex = event.index;
int chkObjType = objType; int chkObjIndex = objIndex; bool srcIsCondition = (objType == OBJ_SPRITE && sprite[objIndex].type == kModernCondition && objIndex != pSource->index);
if (pXSource->state == 0) { if (pXSource->state == 0) {
// if it's a tracking condition, it must ignore all the commands sent from objects // if it's a tracking condition, it must ignore all the commands sent from objects
if (pXSource->busyTime > 0 && event.funcID != kCallbackCondition) if (pXSource->busyTime > 0 && event.funcID != kCallbackCondition)
return; return false;
// save object in the stack // and keep the copy // save object in the stack and make copy of initial object
pXSource->targetX = objType; pXSource->targetY = objIndex; if (!srcIsCondition)
pXSource->target = objType; pXSource->targetZ = objIndex; pXSource->targetX = pXSource->targetY = condSerialize(objType, objIndex);
// only first condition in sequence can use waitTime? // only first condition in sequence can use waitTime?
if (pXSource->waitTime > 0 && (objType != OBJ_SPRITE || sprite[objIndex].type != kModernCondition)) { if (pXSource->waitTime > 0 && !srcIsCondition) {
pXSource->state = 1; pXSource->state = 1;
if (pXSource->busyTime > 0) evKill(pSource->index, OBJ_SPRITE, kCallbackCondition); if (pXSource->busyTime > 0) evKill(pSource->index, OBJ_SPRITE, kCallbackCondition);
evPost(pSource->index, OBJ_SPRITE, (pXSource->waitTime * 60) / 10, kCmdRepeat); evPost(pSource->index, OBJ_SPRITE, (pXSource->waitTime * 60) / 10, kCmdRepeat);
return; return false;
} }
} else if (event.cmd == kCmdRepeat || pXSource->Interrutable) { } else if (event.cmd == kCmdRepeat || pXSource->Interrutable) {
@ -3720,40 +3766,56 @@ void useCondition(XSPRITE* pXSource, EVENT event) {
evPost(pSource->index, OBJ_SPRITE, 0, kCallbackCondition); evPost(pSource->index, OBJ_SPRITE, 0, kCallbackCondition);
} else { } else {
return; return false;
} }
if (objType == OBJ_SPRITE && sprite[objIndex].type == kModernCondition) { // grab serials of objects from previous conditions
objType = pXSource->targetX = xsprite[sprite[objIndex].extra].targetX; if (srcIsCondition) {
objIndex = pXSource->targetY = xsprite[sprite[objIndex].extra].targetY; pXSource->targetX = xsprite[sprite[objIndex].extra].targetX;
pXSource->targetY = xsprite[sprite[objIndex].extra].targetY;
chkObjType = xsprite[sprite[chkObjIndex].extra].target;
chkObjIndex = xsprite[sprite[chkObjIndex].extra].targetZ;
} }
// 100 - 200: universal conditions // 200 - 300: wall specific conditions // 100 - 200: universal conditions // 200 - 300: wall specific conditions
// 300 - 400: sector specific conditions // 500 - 600: sprite specific conditions // 300 - 400: sector specific conditions // 500 - 600: sprite specific conditions
int cond = pXSource->data1; bool ok = false; int cond = pXSource->data1; bool ok = false; int cmpOp = pSource->cstat; // comparison operator
bool PUSH = (pXSource->command == kCmdNumberic); bool RVRS = (pSource->yvel == kModernConditionFalse); bool PUSH = (pXSource->command == kCmdNumberic); bool RVRS = (pSource->yvel == kModernConditionFalse);
bool RSTR = (pXSource->command == kCmdNumberic + 26); bool RSET = (pXSource->command == kCmdNumberic + 36);
if (condCmpr(cond, kCondMixedBase, kCondMixedMax)) ok = condCheckMixed(pXSource, event, PUSH, RVRS); condUnserialize(pXSource->targetX, &objType, &objIndex);
else if (condCmpr(cond, kCondWallBase, kCondWallMax)) ok = condCheckWall(pXSource, PUSH, RVRS); if (cond >= kCondMixedBase && cond < kCondMixedMax) ok = condCheckMixed(pXSource, event, cmpOp, PUSH, RVRS);
else if (condCmpr(cond, kCondSectorBase, kCondSectorMax)) ok = condCheckSector(pXSource, PUSH, RVRS); else if (cond >= kCondWallBase && cond < kCondWallMax) ok = condCheckWall(pXSource, cmpOp, PUSH, RVRS);
else if (condCmpr(cond, kCondDudeBase, kCondDudeMax)) ok = condCheckDude(pXSource, PUSH, RVRS); else if (cond >= kCondSectorBase && cond < kCondSectorMax) ok = condCheckSector(pXSource, cmpOp, PUSH, RVRS);
else if (condCmpr(cond, kCondSpriteBase, kCondSpriteMax)) ok = condCheckSprite(pXSource, PUSH, RVRS); else if (cond >= kCondDudeBase && cond < kCondDudeMax) ok = condCheckDude(pXSource, cmpOp, PUSH, RVRS);
else if (cond >= kCondSpriteBase && cond < kCondSpriteMax) ok = condCheckSprite(pXSource, cmpOp, PUSH, RVRS);
else ThrowError("\nUnexpected condition id %d!\n Condition RX ID: %d, SPRITE #%d", cond, pXSource->rxID, pSource->index); else ThrowError("\nUnexpected condition id %d!\n Condition RX ID: %d, SPRITE #%d", cond, pXSource->rxID, pSource->index);
if (ok ^ RVRS) { if (ok ^ RVRS) {
//viewSetSystemMessage("TRIGGER COND: %d, RVRS: %d", cond, RVRS);
if (RSTR) condRestore(pXSource); pXSource->isTriggered = (pXSource->triggerOnce) ? true : false;
if (pXSource->triggerOnce) pXSource->isTriggered = true; if (RSET) condRestore(pXSource); // restore initial object
if (pSource->flags & kModernTypeFlag1) evPost(chkObjIndex, chkObjType, 0, (COMMAND_ID)pXSource->command); // send it only for object that pass condition
else evSend(pXSource->reference, OBJ_SPRITE, pXSource->txID, (COMMAND_ID)pXSource->command); // send it for whole rx bucket // send command to rx bucket
if (pXSource->txID)
evSend(pSource->index, OBJ_SPRITE, pXSource->txID, (COMMAND_ID)pXSource->command);
if (pSource->hitag) {
// send it for current object (before pushing)
if (pSource->hitag & kModernTypeFlag1)
nnExtTriggerObject(objType, objIndex, pXSource->command);
// send it for initial object
if ((pSource->hitag & kModernTypeFlag2) && (pXSource->targetX != pXSource->targetY || !(pSource->hitag & kModernTypeFlag1))) {
condUnserialize(pXSource->targetY, &objType, &objIndex);
nnExtTriggerObject(objType, objIndex, pXSource->command);
}
} }
return; return true;
}
return false;
} }
void useRandomItemGen(spritetype* pSource, XSPRITE* pXSource) { void useRandomItemGen(spritetype* pSource, XSPRITE* pXSource) {

View file

@ -118,15 +118,22 @@ OBJ_SECTOR = 6,
enum { enum {
kCondMixedBase = 100, kCondMixedBase = 100,
kCondMixedMax = 199, kCondMixedMax = 200,
kCondWallBase = 200, kCondWallBase = 200,
kCondWallMax = 299, kCondWallMax = 300,
kCondSectorBase = 300, kCondSectorBase = 300,
kCondSectorMax = 399, kCondSectorMax = 400,
kCondDudeBase = 400, kCondDudeBase = 400,
kCondDudeMax = 499, kCondDudeMax = 500,
kCondSpriteBase = 500, kCondSpriteBase = 500,
kCondSpriteMax = 599, kCondSpriteMax = 600,
};
enum {
kCondSerialSector = 100000,
kCondSerialWall = 200000,
kCondSerialSprite = 300000,
kCondSerialMax = 400000,
}; };
// - STRUCTS ------------------------------------------------------------------ // - STRUCTS ------------------------------------------------------------------
@ -214,6 +221,7 @@ void nnExtProcessSuperSprites(void);
bool nnExtIsImmune(spritetype* pSprite, int dmgType, int minScale = 16); bool nnExtIsImmune(spritetype* pSprite, int dmgType, int minScale = 16);
int nnExtRandom(int a, int b); int nnExtRandom(int a, int b);
void nnExtResetGlobals(); void nnExtResetGlobals();
void nnExtTriggerObject(int objType, int objIndex, int command);
// ------------------------------------------------------------------------- // // ------------------------------------------------------------------------- //
spritetype* randomDropPickupObject(spritetype* pSprite, short prevItem); spritetype* randomDropPickupObject(spritetype* pSprite, short prevItem);
spritetype* randomSpawnDude(spritetype* pSprite); spritetype* randomSpawnDude(spritetype* pSprite);
@ -318,13 +326,16 @@ 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); XSPRITE* eventRedirected(int objType, int objXIndex, bool byRx);
void 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 condCmpr(int val, int min, int max); bool condRestore(XSPRITE* pXSprite);
bool condCheckMixed(XSPRITE* pXCond, EVENT event, bool PUSH, bool RVRS); bool condCmp(int val, int arg1, int arg2, int comOp);
bool condCheckSector(XSPRITE* pXCond, bool PUSH, bool RVRS); bool condCmpne(int arg1, int arg2, int comOp);
bool condCheckWall(XSPRITE* pXCond, bool PUSH, bool RVRS); /*bool condCmpr(int val, int min, int max, int cmpOp);*/
bool condCheckSprite(XSPRITE* pXCond, bool PUSH, bool RVRS); bool condCheckMixed(XSPRITE* pXCond, EVENT event, int cmpOp, bool PUSH, bool RVRS);
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);
#endif #endif
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////

View file

@ -331,6 +331,10 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
{ {
spritetype *pSprite = &sprite[nSprite]; spritetype *pSprite = &sprite[nSprite];
#ifdef NOONE_EXTENSIONS
if (gModernMap && modernTypeOperateSprite(nSprite, pSprite, pXSprite, event))
return;
#else
switch (event.cmd) { switch (event.cmd) {
case kCmdLock: case kCmdLock:
pXSprite->locked = 1; pXSprite->locked = 1;
@ -342,10 +346,6 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
pXSprite->locked = pXSprite->locked ^ 1; pXSprite->locked = pXSprite->locked ^ 1;
return; return;
} }
#ifdef NOONE_EXTENSIONS
if (gModernMap && modernTypeOperateSprite(nSprite, pSprite, pXSprite, event))
return;
#endif #endif
if (pSprite->statnum == kStatDude && pSprite->type >= kDudeBase && pSprite->type < kDudeMax) { if (pSprite->statnum == kStatDude && pSprite->type >= kDudeBase && pSprite->type < kDudeMax) {
@ -2168,7 +2168,7 @@ void trInit(void)
evPost(i, 3, (pXSprite->waitTime * 120) / 10, pXSprite->restState ? kCmdOn : kCmdOff); evPost(i, 3, (pXSprite->waitTime * 120) / 10, pXSprite->restState ? kCmdOn : kCmdOff);
break; break;
case kModernCondition: case kModernCondition:
if (pXSprite->busyTime <= 0) break; if (pXSprite->busyTime <= 0 || pXSprite->locked) break;
evPost(i, 3, ClipLow(pXSprite->busyTime, 5), kCallbackCondition); evPost(i, 3, ClipLow(pXSprite->busyTime, 5), kCallbackCondition);
break; break;
#endif #endif