diff --git a/source/blood/src/actor.cpp b/source/blood/src/actor.cpp index 147150986..e09633c92 100644 --- a/source/blood/src/actor.cpp +++ b/source/blood/src/actor.cpp @@ -2557,9 +2557,6 @@ short gSightSpritesCount; // current count short gPhysSpritesList[]; // by NoOne: list of additional sprites which can be affected by physics short gPhysSpritesCount; // current count - -short gQavPlayerIndex = -1; // by NoOne: index of sprite which currently activated to play qav - void actInit(bool bSaveLoad) { // by NoOne: init code for all my stuff @@ -2584,12 +2581,14 @@ void actInit(bool bSaveLoad) { getSpriteMassBySize(pSprite); // create mass cache break; } - + // init after loading save file if (bSaveLoad) { - + // add in list of physics affected sprites if (pXSprite->physAttr != 0) { + //xvel[pSprite->index] = yvel[pSprite->index] = zvel[pSprite->index] = 0; + gPhysSpritesList[gPhysSpritesCount++] = pSprite->index; // add sprite index getSpriteMassBySize(pSprite); // create mass cache } @@ -2634,7 +2633,7 @@ void actInit(bool bSaveLoad) { else { gProxySpritesList[gProxySpritesCount++] = pSprite->xvel; if (gProxySpritesCount == kMaxSuperXSprites) - viewSetSystemMessage("Max (%d) *additional* Proximity sprites reached!", kMaxSuperXSprites); + ThrowError("Max (%d) *additional* Proximity sprites reached!", kMaxSuperXSprites); } break; } @@ -2658,7 +2657,7 @@ void actInit(bool bSaveLoad) { default: gSightSpritesList[gSightSpritesCount++] = pSprite->xvel; if (gSightSpritesCount == kMaxSuperXSprites) - viewSetSystemMessage("Max (%d) Sight sprites reached!", kMaxSuperXSprites); + ThrowError("Max (%d) Sight sprites reached!", kMaxSuperXSprites); break; } } @@ -2691,7 +2690,11 @@ void actInit(bool bSaveLoad) { int nType = pSprite->type - kThingBase; pXSprite->health = thingInfo[nType].startHealth << 4; - pSprite->clipdist = thingInfo[nType].clipdist; + // by NoOne: allow level designer to set custom clipdist. + // this is especially useful for various Gib and Explode objects which have clipdist 1 for some reason predefined, + // but what if it have voxel model...? + if (!gModernMap) pSprite->clipdist = thingInfo[nType].clipdist; + pSprite->flags = thingInfo[nType].flags; if (pSprite->flags & kPhysGravity) pSprite->flags |= kPhysFalling; xvel[nSprite] = yvel[nSprite] = zvel[nSprite] = 0; @@ -4259,16 +4262,17 @@ void ProcessTouchObjects(spritetype *pSprite, int nXSprite) break; case kDudeModernCustom: case kDudeModernCustomBurning: - int dmg = (getSpriteMassBySize(pSprite2) - getSpriteMassBySize(pSprite)) + pSprite2->clipdist; - if (dmg > 0) { - if (IsPlayerSprite(pSprite) && powerupCheck(&gPlayer[pSprite->type - kDudePlayer1], kPwUpJumpBoots) > 0) - actDamageSprite(pSprite2->xvel, pSprite, DAMAGE_TYPE_3, dmg); - else - actDamageSprite(pSprite2->xvel, pSprite, DAMAGE_TYPE_0, dmg); - } + int dmg = 0; + if (!IsDudeSprite(pSprite) || (dmg = ClipLow((getSpriteMassBySize(pSprite2) - getSpriteMassBySize(pSprite)) >> 1, 0)) == 0) + break; - if (!IsPlayerSprite(pSprite) && pSprite2->extra >= 0 && !isActive(pSprite2->xvel)) - aiActivateDude(pSprite2, &xsprite[pSprite2->extra]); + if (!IsPlayerSprite(pSprite)) { + actDamageSprite(pSprite2->index, pSprite, DAMAGE_TYPE_0, dmg); + if (xspriRangeIsFine(pSprite->extra) && !isActive(pSprite->index)) + aiActivateDude(pSprite, &xsprite[pSprite->extra]); + } + else if (powerupCheck(&gPlayer[pSprite->type - kDudePlayer1], kPwUpJumpBoots) > 0) actDamageSprite(pSprite2->index, pSprite, DAMAGE_TYPE_3, dmg); + else actDamageSprite(pSprite2->index, pSprite, DAMAGE_TYPE_0, dmg); break; } @@ -4483,7 +4487,7 @@ void ProcessTouchObjects(spritetype *pSprite, int nXSprite) } // by NoOne: add more trigger statements for Touch flag - if (gModernMap) { + if (gModernMap && IsDudeSprite(pSprite)) { // Touch sprites int nHSprite = -1; @@ -4494,7 +4498,7 @@ void ProcessTouchObjects(spritetype *pSprite, int nXSprite) else if ((gSpriteHit[nXSprite].ceilhit & 0xc000) == 0xc000) nHSprite = gSpriteHit[nXSprite].ceilhit & 0x3fff; - if (nHSprite >= 0 && sprite[nHSprite].extra >= 0) { + if (spriRangeIsFine(nHSprite) && xspriRangeIsFine(sprite[nHSprite].extra)) { XSPRITE* pXHSprite = &xsprite[sprite[nHSprite].extra]; if (pXHSprite->Touch && !pXHSprite->isTriggered && (!pXHSprite->DudeLockout || IsPlayerSprite(pSprite))) trTriggerSprite(nHSprite, pXHSprite, kCmdSpriteTouch, nSprite); @@ -4503,12 +4507,14 @@ void ProcessTouchObjects(spritetype *pSprite, int nXSprite) // Touch walls int nHWall = -1; if ((gSpriteHit[nXSprite].hit & 0xc000) == 0x8000) { - if ((nHWall = gSpriteHit[nXSprite].hit & 0x3fff) >= 0 && wall[nHWall].extra >= 0) { + nHWall = gSpriteHit[nXSprite].hit & 0x3fff; + if (wallRangeIsFine(nHWall) && xwallRangeIsFine(wall[nHWall].extra)) { XWALL* pXHWall = &xwall[wall[nHWall].extra]; if (pXHWall->triggerTouch && !pXHWall->isTriggered && (!pXHWall->dudeLockout || IsPlayerSprite(pSprite))) trTriggerWall(nHWall, pXHWall, kCmdWallTouch, nSprite); } } + } } @@ -4788,15 +4794,9 @@ void MoveDude(spritetype *pSprite) gHitInfo = hitInfo; } - if (pHitXSprite && pHitXSprite->Touch && !pHitXSprite->isTriggered) { - - // by NoOne: do not check state (so, things can work with touch too) and allow dudelockout - if ((gModernMap) && (!pHitXSprite->DudeLockout || IsPlayerSprite(pSprite))) - trTriggerSprite(nHitSprite, pHitXSprite, kCmdSpriteTouch, nSprite); - else if (!pHitXSprite->state) // or check like vanilla do - trTriggerSprite(nHitSprite, pHitXSprite, kCmdSpriteTouch, nSprite); - } - + if (!gModernMap && pHitXSprite && pHitXSprite->Touch && !pHitXSprite->state && !pHitXSprite->isTriggered) + trTriggerSprite(nHitSprite, pHitXSprite, kCmdSpriteTouch, nSprite); + if (pDudeInfo->lockOut && pHitXSprite && pHitXSprite->Push && !pHitXSprite->key && !pHitXSprite->DudeLockout && !pHitXSprite->state && !pHitXSprite->busy && !pPlayer) trTriggerSprite(nHitSprite, pHitXSprite, kCmdSpritePush, nSprite); @@ -5663,10 +5663,9 @@ void actProcessSprites(void) // by NoOne: process Debris sprites for movement if (gPhysSpritesCount > 0) { - //System.err.println("PHYS COUNT: "+gPhysSpritesCount); + //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) { gPhysSpritesList[i] = -1; continue; @@ -5680,7 +5679,6 @@ void actProcessSprites(void) spritetype* pDebris = &sprite[gPhysSpritesList[i]]; XSECTOR* pXSector = (sector[pDebris->sectnum].extra >= 0) ? &xsector[sector[pDebris->sectnum].extra] : NULL; - viewBackupSpriteLoc(pDebris->xvel, pDebris); int airVel = gSpriteMass[pDebris->extra].airVel; if (pXSector != NULL) { diff --git a/source/blood/src/aiunicult.cpp b/source/blood/src/aiunicult.cpp index 8a8ca5d3a..5396e358c 100644 --- a/source/blood/src/aiunicult.cpp +++ b/source/blood/src/aiunicult.cpp @@ -188,7 +188,8 @@ void genDudeProcess(spritetype* pSprite, XSPRITE* pXSprite) { if (pXSprite->stateTimer == 0 && pXSprite->aiState->nextState && (pXSprite->aiState->stateTicks > 0 || seqGetStatus(3, pSprite->extra) < 0)) aiGenDudeNewState(pSprite, pXSprite->aiState->nextState); - if (pXSprite->health > 0 && ((dudeInfo[pSprite->type - kDudeBase].hinderDamage << 4) <= cumulDamage[pSprite->extra])) { + int hinder = ((pExtra->isMelee) ? 25 : 5) << 4; + if (pXSprite->health > 0 && hinder <= cumulDamage[pSprite->extra]) { pXSprite->data3 = cumulDamage[pSprite->extra]; RecoilDude(pSprite, pXSprite); } diff --git a/source/blood/src/dude.cpp b/source/blood/src/dude.cpp index abe2446b7..66d851163 100644 --- a/source/blood/src/dude.cpp +++ b/source/blood/src/dude.cpp @@ -1560,8 +1560,8 @@ DUDEINFO dudeInfo[kDudeMax-kDudeBase] = 618, // melee distance 5, // flee health 5, // hinder damage - 0x0100, // change target chance - 0x0010, // change target to kin chance + 0x0000, // change target chance + 0x0000, // change target to kin chance 0x8000, // alertChance 0, // lockout 46603, // frontSpeed diff --git a/source/blood/src/player.cpp b/source/blood/src/player.cpp index 66e1e1a88..5532c319b 100644 --- a/source/blood/src/player.cpp +++ b/source/blood/src/player.cpp @@ -589,16 +589,24 @@ void deactivateSizeShrooms(PLAYER* pPlayer) { PLAYER* getPlayerById(short id) { - if (id > 0) { + + // relative to connected players + if (id >= 1 && id <= kMaxPlayers) { + id = id - 1; for (int i = connecthead; i >= 0; i = connectpoint2[i]) { - if (id < kMaxPlayers && id == i + 1) return &gPlayer[i]; // relative to connected players - else if (id >= kDudePlayer1 && id <= kDudePlayer8 && id == gPlayer[i].pSprite->type) // absolute type + if (id == gPlayer[i].nPlayer) + return &gPlayer[i]; + } + + // absolute sprite type + } else if (id >= kDudePlayer1 && id <= kDudePlayer8) { + for (int i = connecthead; i >= 0; i = connectpoint2[i]) { + if (id == gPlayer[i].pSprite->type) return &gPlayer[i]; } - - if (id >= kDudePlayer1 && id <= kDudePlayer8) viewSetSystemMessage("There is no player #%d", (kDudePlayer8 - id) + kMaxPlayers); - else viewSetSystemMessage("There is no player #%d", id); } + + viewSetSystemMessage("There is no player id #%d", id); return NULL; } diff --git a/source/blood/src/triggers.cpp b/source/blood/src/triggers.cpp index 8e5a9a763..ec1f2be81 100644 --- a/source/blood/src/triggers.cpp +++ b/source/blood/src/triggers.cpp @@ -440,6 +440,7 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event) // Random Event Switch takes random data field and uses it as TX ID case kModernRandomTX: { + int tx = 0; int maxRetries = 10; // set range of TX ID if data2 and data3 is empty. if (pXSprite->data1 > 0 && pXSprite->data2 <= 0 && pXSprite->data3 <= 0 && pXSprite->data4 > 0) { @@ -456,7 +457,7 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event) // use true random only for single player mode, otherwise use Blood's default one. if (gGameOptions.nGameType == 0 && !VanillaMode() && !DemoRecordStatus()) tx = STD_Random(pXSprite->data1, pXSprite->data4); else tx = Random(total) + pXSprite->data1; - + if (tx != pXSprite->txID) break; maxRetries--; } @@ -472,7 +473,6 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event) SetSpriteState(nSprite, pXSprite, pXSprite->state ^ 1, event.causedBy); } return; - // Sequential Switch takes values from data fields starting from data1 and uses it as TX ID case kModernSequentialTX: { bool range = false; int cnt = 3; int tx = 0; @@ -862,14 +862,18 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event) TRPLAYERCTRL* pCtrl = &gPlayerCtrl[pPlayer->nPlayer]; if (event.cmd >= kCmdNumberic) { switch (event.cmd) { - case kCmdNumberic + 3:// start playing qav scene + case kCmdNumberic + 3: // start playing qav scene if (pCtrl->qavScene.index != nSprite || pXSprite->Interrutable) trPlayerCtrlStartScene(pXSprite, pPlayer, event.causedBy); return; - case kCmdNumberic + 4: // stop playing qav scene - if (pCtrl->qavScene.index == nSprite || event.type != 3 || sprite[event.index].type != kModernPlayerControl) + case kCmdNumberic + 4: { // stop playing qav scene + int scnIndex = pCtrl->qavScene.index; + if (spriRangeIsFine(scnIndex) && (scnIndex == nSprite || event.type != 3 || sprite[event.index].type != kModernPlayerControl)) { + if (scnIndex != nSprite) pXSprite = &xsprite[sprite[scnIndex].extra]; trPlayerCtrlStopScene(pXSprite, pPlayer); + } return; + } default: oldCmd = pXSprite->command; pXSprite->command = event.cmd; // convert event command to current sprite command @@ -993,8 +997,8 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event) // angle // TO-DO: if tx > 0, take a look on TX ID sprite - if (pXSprite->data3 == 1) pPlayer->pSprite->ang = pXSprite->data3; - else if (valueIsBetween(pXSprite->data3, 0, kAng180)) + if (pXSprite->data3 == 1) pPlayer->pSprite->ang = pSprite->ang; + else if (valueIsBetween(pXSprite->data3, 1, kAng180)) pPlayer->pSprite->ang = pXSprite->data3; } //viewSetSystemMessage("ANGLE: %d, SLOPE: %d", pPlayer->pSprite->ang, pPlayer->q16look); @@ -1070,7 +1074,9 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event) pPlayer->hasWeapon[pXSprite->data3] = true; if (pXSprite->data4 == 0) { // switch on it - if (pPlayer->sceneQav >= 0) { + pPlayer->nextWeapon = 0; + + if (pPlayer->sceneQav >= 0 && spriRangeIsFine(pCtrl->qavScene.index)) { XSPRITE* pXScene = &xsprite[sprite[pCtrl->qavScene.index].extra]; pXScene->dropMsg = pXSprite->data3; } else if (pPlayer->curWeapon != pXSprite->data3) { @@ -2017,17 +2023,18 @@ void useSectorWindGen(XSPRITE* pXSource, sectortype* pSector) { void useSpriteDamager(XSPRITE* pXSource, spritetype* pSprite) { spritetype* pSource = &sprite[pXSource->reference]; - if (pSprite != NULL && xspriRangeIsFine(pSprite->extra)) { - XSPRITE* pXSprite = &xsprite[pSprite->extra]; - DAMAGE_TYPE dmgType = (DAMAGE_TYPE) ClipRange(pXSource->data2, kDmgFall, kDmgElectric); + if (pSprite != NULL && xspriRangeIsFine(pSprite->extra) && xsprite[pSprite->extra].health > 0) { + DAMAGE_TYPE dmgType = (DAMAGE_TYPE)ClipRange(pXSource->data2, kDmgFall, kDmgElectric); int dmg = (pXSource->data3 == 0) ? 65535 : ClipRange(pXSource->data3 << 1, 1, 65535); if (pXSource->data2 >= 0) actDamageSprite(pSource->index, pSprite, dmgType, dmg); else if (pXSource->data2 == -1 && IsDudeSprite(pSprite)) { PLAYER* pPlayer = getPlayerById(pSprite->type); if (pPlayer == NULL || !pPlayer->godMode) { xsprite[pSprite->extra].health = ClipLow(xsprite[pSprite->extra].health - dmg, 0); - if (xsprite[pSprite->extra].health == 0) - actKillDude(pSource->index, pSprite, DAMAGE_TYPE_0, 65535); + if (xsprite[pSprite->extra].health == 0) { + if (pPlayer == NULL) actKillDude(pSource->index, pSprite, DAMAGE_TYPE_0, 4); + else playerDamageSprite(pSource->index, pPlayer, DAMAGE_TYPE_0, 4); + } } } } @@ -3450,18 +3457,18 @@ void pastePropertiesInObj(int type, int nDest, EVENT event) { if (event.type != 3) return; spritetype* pSource = &sprite[event.index]; - if (pSource->extra < 0) return; + if (!xspriRangeIsFine(pSource->extra)) return; XSPRITE* pXSource = &xsprite[pSource->extra]; switch (type) { case 6: - if (sector[nDest].extra < 0) return; + if (!xsectRangeIsFine(sector[nDest].extra)) return; break; case 0: - if (wall[nDest].extra < 0) return; + if (!xwallRangeIsFine(wall[nDest].extra)) return; break; case 3: - if (sprite[nDest].extra < 0) return; + if (!xspriRangeIsFine(sprite[nDest].extra)) return; break; default: return; @@ -3475,7 +3482,7 @@ void pastePropertiesInObj(int type, int nDest, EVENT event) { } else if (pSource->type == kModernSpriteDamager) { /* - damages xsprite via TX ID - */ if (type != 3) return; - else if (xsprite[sprite[nDest].extra].health > 0) useSpriteDamager(pXSource, &sprite[nDest]); + useSpriteDamager(pXSource, &sprite[nDest]); return; } if (pSource->type == kModernEffectSpawner) {