diff --git a/platform/Windows/audiolib.vcxproj b/platform/Windows/audiolib.vcxproj index 5abd7fbb3..4583f380e 100644 --- a/platform/Windows/audiolib.vcxproj +++ b/platform/Windows/audiolib.vcxproj @@ -189,7 +189,6 @@ - @@ -209,8 +208,6 @@ - - true @@ -223,21 +220,17 @@ - - - - diff --git a/platform/Windows/audiolib.vcxproj.filters b/platform/Windows/audiolib.vcxproj.filters index 29fbe0a84..156732589 100644 --- a/platform/Windows/audiolib.vcxproj.filters +++ b/platform/Windows/audiolib.vcxproj.filters @@ -56,9 +56,6 @@ Source Files - - Source Files - Source Files @@ -71,12 +68,6 @@ Source Files - - Source Files - - - Source Files - @@ -109,29 +100,17 @@ Header Files - - Header Files - Header Files Header Files - - Header Files - Header Files Header Files - - Header Files - - - Header Files - \ No newline at end of file diff --git a/source/blood/src/actor.cpp b/source/blood/src/actor.cpp index 2b53e94bb..4c1e4d9ea 100644 --- a/source/blood/src/actor.cpp +++ b/source/blood/src/actor.cpp @@ -2524,31 +2524,137 @@ int DudeDifficulty[5] = { 512, 384, 256, 208, 160 }; -void actInit(void) -{ +SPRITEMASS gSpriteMass[]; // by NoOne: cache for getSpriteMassBySize(); + +short gProxySpritesList[]; // by NoOne: list of additional sprites which can be triggered by Proximity +short gProxySpritesCount; // current count + +short gSightSpritesList[]; // by NoOne: list of additional sprites which can be triggered by Sight +short gSightSpritesCount; // current count + +short gPhysSpritesList[]; // by NoOne: list of additional sprites which can be affected by physics +short gPhysSpritesCount; // current count + +void actInit(bool bSaveLoad) { + + // by NoOne: init code for all my stuff + if (!VanillaMode()) { + + // reset counters + gProxySpritesCount = gSightSpritesCount = gPhysSpritesCount = 0; + + // fill arrays with negative values to avoid xvel 0 situation + memset(gSightSpritesList, -1, sizeof(gSightSpritesList)); + memset(gProxySpritesList, -1, sizeof(gProxySpritesList)); + memset(gPhysSpritesList, -1, sizeof(gPhysSpritesList)); + + for (int i = 0; i < kMaxXSprites; i++) { + + if (xsprite[i].reference < 0) continue; + XSPRITE* pXSprite = &xsprite[i]; spritetype* pSprite = &sprite[pXSprite->reference]; + + switch (pSprite->lotag) { + // add statnum for faster dude searching + case kGDXDudeTargetChanger: + changespritestat(i, kStatGDXDudeTargetChanger); + break; + // remove kStatItem status from random item generators + case 40: // Random weapon + case 80: // Random ammo + changespritestat(i, 0); + break; + case kCustomDude: + case kCustomDudeBurning: + getSpriteMassBySize(pSprite); // create mass cache + break; + } + + // init after loading save file + if (bSaveLoad) { + + // add in list of physics affected sprites + if (pXSprite->physAttr != 0) { + gPhysSpritesList[gPhysSpritesCount++] = pSprite->index; // add sprite index + getSpriteMassBySize(pSprite); // create mass cache + } + + if (pXSprite->data3 != pXSprite->sysData1) { + switch (pSprite->statnum) { + case 6: + switch (pSprite->lotag) { + case kCustomDude: + case kCustomDudeBurning: + pXSprite->data3 = pXSprite->sysData1; // move sndStartId back from sysData1 to data3 + break; + } + break; + } + } + } + + // make Proximity flag work not just for dudes and things... + if (pXSprite->Proximity && gProxySpritesCount < kMaxSuperXSprites) { + switch (pSprite->statnum) { + // exceptions + case 4: // things already treated in their functions + case 6: // enemies already treated in their functions + // senseless to have sight and proximity together + if (pXSprite->Sight && pXSprite->DudeLockout) pXSprite->Proximity = false; + break; + case 1: // effects + case 2: // explosions + case 3: // items + case 9: // purgeable sprites + case 13: // ??? + case 14: // burning flares stuck + case 7: // inactive enemies + case kStatFree: // removed sprites + case kStatMarker: // markers + case 16: // path markers + break; + default: + // senseless to have sight and proximity together + if (pXSprite->Sight && pXSprite->DudeLockout) pXSprite->Proximity = false; + else { + gProxySpritesList[gProxySpritesCount++] = pSprite->xvel; + if (gProxySpritesCount == kMaxSuperXSprites) + ThrowError("Max (%d) *additional* Proximity sprites reached!",kMaxSuperXSprites); + } + break; + } + } + + // make Sight flag work not just for dudes and things... + if (pXSprite->Sight && gSightSpritesCount < kMaxSuperXSprites) { + switch (pSprite->statnum) { + // exceptions + case 1: // effects + case 2: // explosions + case 3: // items + case 9: // purgeable sprites + case 13: // ??? + case 14: // burning flares stuck + case 7: // inactive enemies + case kStatFree: // removed sprites + case kStatMarker: // markers + case 16: // path markers + break; + default: + gSightSpritesList[gSightSpritesCount++] = pSprite->xvel; + if (gSightSpritesCount == kMaxSuperXSprites) + ThrowError("Max (%d) Sight sprites reached!", kMaxSuperXSprites); + break; + } + } + } + } + for (int nSprite = headspritestat[3]; nSprite >= 0; nSprite = nextspritestat[nSprite]) { spritetype *pSprite = &sprite[nSprite]; if (pSprite->type == 44) // Voodoo doll (ammo) pSprite->type = 70; // Voodoo doll (weapon) - switch (pSprite->type) { - case 44: - pSprite->type = 70; - break; - - // By NoOne: add Random pickup feature - case 40: // Random weapon - case 80: // Random ammo - - // Make sprites invisible and non-blocking - pSprite->cstat &= ~CSTAT_SPRITE_BLOCK; - pSprite->cstat |= CSTAT_SPRITE_INVISIBLE; - - if (pSprite->extra > 0 && xsprite[pSprite->extra].state == 1) - trTriggerSprite(nSprite, &xsprite[pSprite->extra], COMMAND_ID_0); - break; - } } for (int nSprite = headspritestat[11]; nSprite >= 0; nSprite = nextspritestat[nSprite]) { @@ -2620,6 +2726,8 @@ void actInit(void) } else { + // by NoOne: WTF is this? + /////////////// char unk[kDudeMax-kDudeBase]; memset(unk, 0, sizeof(unk)); for (int nSprite = headspritestat[6]; nSprite >= 0; nSprite = nextspritestat[nSprite]) @@ -2629,28 +2737,36 @@ void actInit(void) ThrowError("Non-enemy sprite (%d) in the enemy sprite list.\n", nSprite); unk[pSprite->type-kDudeBase] = 1; } + gKillMgr.sub_2641C(); + /////////////// + for (int i = 0; i < kDudeMax-kDudeBase; i++) for (int j = 0; j < 7; j++) dudeInfo[i].at70[j] = mulscale8(DudeDifficulty[gGameOptions.nDifficulty], dudeInfo[i].startDamage[j]); - for (int nSprite = headspritestat[6]; nSprite >= 0; nSprite = nextspritestat[nSprite]) - { + + for (int nSprite = headspritestat[6]; nSprite >= 0; nSprite = nextspritestat[nSprite]) { spritetype *pSprite = &sprite[nSprite]; int nXSprite = pSprite->extra; dassert(nXSprite > 0 && nXSprite < kMaxXSprites); XSPRITE *pXSprite = &xsprite[nXSprite]; int nType = pSprite->type-kDudeBase; - if (!IsPlayerSprite(pSprite)) - { - pSprite->cstat |= 4096+256+1; - - // By NoOne: allow user clipdist for custom dude. + int seqStartId = dudeInfo[nType].seqStartID; + if (!IsPlayerSprite(pSprite)) { + switch (pSprite->type) { - case kGDXDudeUniversalCultist: - case kGDXGenDudeBurning: + case 225: // by NoOne: FakeDude type (no seq, custom hitag, clipdist and cstat) + break; + case kCustomDude: + case kCustomDudeBurning: + pSprite->cstat |= 4096 + 256 + 1; + seqStartId = getSeqStartId(pXSprite); // by NoOne: Custom Dude stores it's SEQ in data2 + pXSprite->sysData1 = pXSprite->data3; // by NoOne move sndStartId to sysData1, because data3 used by the game; + pXSprite->data3 = 0; break; default: pSprite->clipdist = dudeInfo[nType].clipdist; + pSprite->cstat |= 4096 + 256 + 1; break; } @@ -2658,47 +2774,10 @@ void actInit(void) // By NoOne: add a way to set custom hp for every enemy - should work only if map just started and not loaded. if (pXSprite->data4 <= 0) pXSprite->health = dudeInfo[nType].startHealth << 4; - else { - long hp = pXSprite->data4 << 4; - pXSprite->health = (hp > 0) ? ((hp <= 65535) ? hp : 65535) : 1; - } + else pXSprite->health = ClipRange(pXSprite->data4 << 4, 1, 65535); + } - int seqStartId = dudeInfo[nType].seqStartID; - // By NoOne: store seqStartId in data2 field for custom dude - if (pSprite->type == kGDXDudeUniversalCultist) { - - if (pXSprite->data2 > 0) { - seqStartId = pXSprite->data2; - int seqEndId = pXSprite->data2 + 19; - - // check for full set of animations - for (int i = seqStartId; i <= seqEndId; i++) { - - // exceptions - switch (i - seqStartId) { - case 3: - case 4: - case 11: - case 12: - case 18: - case 19: - continue; - } - - if (!gSysRes.Lookup(i, "SEQ")) { - //ThrowError("No SEQ file found for custom dude!"); - pXSprite->data2 = dudeInfo[nType].seqStartID; - seqStartId = pXSprite->data2; - break; - } - } - - } else { - pXSprite->data2 = seqStartId; - } - } - if (gSysRes.Lookup(seqStartId, "SEQ")) seqSpawn(seqStartId, 3, nXSprite); } aiInit(); @@ -2720,9 +2799,9 @@ void ConcussSprite(int a1, spritetype *pSprite, int x, int y, int z, int a6) if (IsDudeSprite(pSprite)) { mass = dudeInfo[pSprite->lotag - kDudeBase].mass; switch (pSprite->lotag) { - case kGDXDudeUniversalCultist: - case kGDXGenDudeBurning: - mass = getDudeMassBySpriteSize(pSprite); + case kCustomDude: + case kCustomDudeBurning: + mass = getSpriteMassBySize(pSprite); break; } } @@ -3030,13 +3109,10 @@ void actKillDude(int a1, spritetype *pSprite, DAMAGE_TYPE a3, int a4) int nXSprite = pSprite->extra; dassert(nXSprite > 0); XSPRITE *pXSprite = &xsprite[pSprite->extra]; - switch (pSprite->type) - { - case kGDXDudeUniversalCultist: - { + switch (pSprite->type) { + case kCustomDude: { removeDudeStuff(pSprite); - XSPRITE* pXIncarnation = getNextIncarnation(pXSprite); - if (pXIncarnation == NULL) { + if (pXSprite->txID <= 0 || getNextIncarnation(pXSprite) == NULL) { if (pXSprite->data1 >= 459 && pXSprite->data1 < (459 + kExplodeMax) - 1 && Chance(0x4000) && a3 != 5 && a3 != 4) { @@ -3048,8 +3124,8 @@ void actKillDude(int a1, spritetype *pSprite, DAMAGE_TYPE a3, int a4) if (a3 == DAMAGE_TYPE_1) { if ((gSysRes.Lookup(pXSprite->data2 + 15, "SEQ") || gSysRes.Lookup(pXSprite->data2 + 16, "SEQ")) && pXSprite->medium == 0) { if (gSysRes.Lookup(pXSprite->data2 + 3, "SEQ")) { - pSprite->type = kGDXGenDudeBurning; - if (pXSprite->data2 == 11520) // don't inherit palette for burning if using default animation + pSprite->type = kCustomDudeBurning; + if (pXSprite->data2 == kDefaultAnimationBase) // don't inherit palette for burning if using default animation pSprite->pal = 0; aiNewState(pSprite, pXSprite, &GDXGenDudeBurnGoto); @@ -3067,10 +3143,23 @@ void actKillDude(int a1, spritetype *pSprite, DAMAGE_TYPE a3, int a4) } } else { + + pXSprite->locked = 1; // lock while transforming + + aiSetGenIdleState(pSprite, pXSprite); // set idle state + + if (pXSprite->key > 0) // drop keys + actDropObject(pSprite, 100 + pXSprite->key - 1); + + if (pXSprite->dropMsg > 0) // drop items + actDropObject(pSprite, pXSprite->dropMsg); + + pSprite->hitag &= ~kPhysMove; xvel[pSprite->index] = yvel[pSprite->index] = 0; + int seqId = pXSprite->data2 + 18; if (!gSysRes.Lookup(seqId, "SEQ")) { seqKill(3, nXSprite); - sfxPlayGDXGenDudeSound(pSprite, 10, pXSprite->data3); + sfxPlayGDXGenDudeSound(pSprite, 10); spritetype* pEffect = gFX.fxSpawn((FX_ID)52, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, pSprite->ang); if (pEffect != NULL) { pEffect->cstat = CSTAT_SPRITE_ALIGNMENT_FACING; @@ -3095,7 +3184,7 @@ void actKillDude(int a1, spritetype *pSprite, DAMAGE_TYPE a3, int a4) return; } seqSpawn(seqId, 3, nXSprite, -1); - sfxPlayGDXGenDudeSound(pSprite, 10, pXSprite->data3); + sfxPlayGDXGenDudeSound(pSprite, 10); return; } break; @@ -3178,9 +3267,9 @@ void actKillDude(int a1, spritetype *pSprite, DAMAGE_TYPE a3, int a4) nSeq = 2; switch (pSprite->type) { - case kGDXDudeUniversalCultist: - case kGDXGenDudeBurning: - sfxPlayGDXGenDudeSound(pSprite, 4, pXSprite->data3); + case kCustomDude: + case kCustomDudeBurning: + sfxPlayGDXGenDudeSound(pSprite, 4); break; case 201: case 202: @@ -3300,23 +3389,27 @@ void actKillDude(int a1, spritetype *pSprite, DAMAGE_TYPE a3, int a4) else seqSpawn(dudeInfo[nType].seqStartID+15, 3, nXSprite, nDudeToGibClient2); break; - case kGDXDudeUniversalCultist: - sfxPlayGDXGenDudeSound(pSprite, 2, pXSprite->data3); + case kCustomDude: + sfxPlayGDXGenDudeSound(pSprite, 2); if (nSeq == 3) { - if (gSysRes.Lookup(pXSprite->data2 + 3, "SEQ")) seqSpawn(3 + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); - else if (gSysRes.Lookup(pXSprite->data2 + 16, "SEQ")) seqSpawn((15 + Random(2)) + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); - else seqSpawn(15 + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); + + bool seq15 = gSysRes.Lookup(pXSprite->data2 + 15, "SEQ"); bool seq16 = gSysRes.Lookup(pXSprite->data2 + 16, "SEQ"); + if (seq15 && seq16) seqSpawn((15 + Random(2)) + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); + else if (seq16) seqSpawn(16 + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); + else if (seq15) seqSpawn(15 + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); + else if (gSysRes.Lookup(pXSprite->data2 + nSeq, "SEQ")) seqSpawn(nSeq + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); + else seqKill(3, nXSprite); - } else { + } else { seqSpawn(nSeq + pXSprite->data2, 3, nXSprite, nDudeToGibClient1); } pXSprite->txID = 0; // to avoid second trigger. break; - case kGDXGenDudeBurning: + case kCustomDudeBurning: { - sfxPlayGDXGenDudeSound(pSprite, 4, pXSprite->data3); + sfxPlayGDXGenDudeSound(pSprite, 4); a3 = DAMAGE_TYPE_3; if (Chance(0x4000)) { @@ -3328,8 +3421,13 @@ void actKillDude(int a1, spritetype *pSprite, DAMAGE_TYPE a3, int a4) } int seqId = pXSprite->data2; - if (gSysRes.Lookup(pXSprite->data2 + 16, "SEQ")) seqSpawn(seqId += 15 + Random(2), 3, nXSprite, nDudeToGibClient1); - else seqSpawn(seqId += 15, 3, nXSprite, nDudeToGibClient1); + bool seq15 = gSysRes.Lookup(pXSprite->data2 + 15, "SEQ"); bool seq16 = gSysRes.Lookup(pXSprite->data2 + 16, "SEQ"); + + if (seq15 && seq16) seqId += (15 + Random(2)); + else if (seq16) seqId += 16; + else seqId += 15; + + seqSpawn(seqId, 3, nXSprite, nDudeToGibClient1); break; } case 241: @@ -3554,13 +3652,13 @@ void actKillDude(int a1, spritetype *pSprite, DAMAGE_TYPE a3, int a4) break; } - // kMaxSprites = custom dude had once life leech - if (pSprite->owner != -1 && pSprite->owner != kMaxSprites) { + // kMaxSprites - 1 = custom dude had once life leech + if (pSprite->owner != -1 && pSprite->owner != (kMaxSprites - 1)) { //int owner = actSpriteIdToOwnerId(pSprite->xvel); int owner = pSprite->owner; switch (sprite[owner].lotag) { - case kGDXDudeUniversalCultist: - case kGDXGenDudeBurning: + case kCustomDude: + case kCustomDudeBurning: if (owner != -1) gDudeExtra[sprite[owner].extra].at6.u1.at4--; break; default: @@ -3670,8 +3768,8 @@ int actDamageSprite(int nSource, spritetype *pSprite, DAMAGE_TYPE a3, int a4) pXSprite->isTriggered = 0; pXSprite->DudeLockout = 0; - if (pSprite->owner >= 0 && sprite[pSprite->owner].type == kGDXDudeUniversalCultist) - sprite[pSprite->owner].owner = kMaxSprites; // By NoOne: indicates if custom dude had life leech. + if (pSprite->owner >= 0 && sprite[pSprite->owner].type == kCustomDude) + sprite[pSprite->owner].owner = kMaxSprites -1; // By NoOne: indicates if custom dude had life leech. } else if (!(pSprite->hitag&16)) actPropagateSpriteOwner(pSprite, &sprite[nSource]); @@ -3830,9 +3928,18 @@ void actImpactMissile(spritetype *pMissile, int a2) int nOwner = actSpriteOwnerToSpriteId(pMissile); DAMAGE_TYPE rand1 = (DAMAGE_TYPE)Random(7); int rand2 = (7+Random(7))<<4; - actDamageSprite(nOwner, pSpriteHit, rand1, rand2); + int nDamage = actDamageSprite(nOwner, pSpriteHit, rand1, rand2); if ((pThingInfo && pThingInfo->at17[DAMAGE_TYPE_1] != 0) || (pDudeInfo && pDudeInfo->at70[DAMAGE_TYPE_1] != 0)) actBurnSprite(pMissile->owner, pXSpriteHit, 360); + + // by NoOne: make Life Leech heal user, just like it was in 1.0x versions + if (gGameOptions.weaponsV10x && !VanillaMode() && !DemoRecordStatus() && pDudeInfo != NULL) { + spritetype* pSource = &sprite[nOwner]; + XSPRITE* pXSource = (pSource->extra >= 0) ? &xsprite[pSource->extra] : NULL; + + if (IsDudeSprite(pSource) && pXSource != NULL && pXSource->health != 0) + actHealDude(pXSource, nDamage >> 2, dudeInfo[pSource->lotag - kDudeBase].startHealth); + } } if (pMissile->extra > 0) { @@ -3927,6 +4034,12 @@ void actImpactMissile(spritetype *pMissile, int a2) evPost(nSpriteHit, 3, 0, CALLBACK_ID_0); actBurnSprite(pMissile->owner, pXSpriteHit, 480); sub_2A620(nOwner, pMissile->x, pMissile->y, pMissile->z, pMissile->sectnum, 16, 20, 10, DAMAGE_TYPE_2, 6, 480, 0, 0); + + // by NoOne: allow additional bullet damage for Flare Gun + if (gGameOptions.weaponsV10x && !VanillaMode() && !DemoRecordStatus()) { + int nDamage = (20 + Random(10)) << 4; + actDamageSprite(nOwner, pSpriteHit, DAMAGE_TYPE_2, nDamage); + } } else { @@ -4170,9 +4283,9 @@ void ProcessTouchObjects(spritetype *pSprite, int nXSprite) int mass1 = dudeInfo[pSprite2->type - kDudeBase].mass; int mass2 = dudeInfo[pSprite->type - kDudeBase].mass; switch (pSprite->type) { - case kGDXDudeUniversalCultist: - case kGDXGenDudeBurning: - mass2 = getDudeMassBySpriteSize(pSprite); + case kCustomDude: + case kCustomDudeBurning: + mass2 = getSpriteMassBySize(pSprite); break; } if (mass1 > mass2) { @@ -4192,9 +4305,9 @@ void ProcessTouchObjects(spritetype *pSprite, int nXSprite) case 229: actDamageSprite(pSprite2->index, pSprite, DAMAGE_TYPE_3, pXSprite->health << 2); break; - case kGDXDudeUniversalCultist: - case kGDXGenDudeBurning: - int dmg = (getDudeMassBySpriteSize(pSprite2) - getDudeMassBySpriteSize(pSprite)) + pSprite2->clipdist; + case kCustomDude: + case kCustomDudeBurning: + int dmg = (getSpriteMassBySize(pSprite2) - getSpriteMassBySize(pSprite)) + pSprite2->clipdist; if (dmg > 0) { if (IsPlayerSprite(pSprite) && powerupCheck(&gPlayer[pSprite->type - kDudePlayer1],15) > 0) actDamageSprite(pSprite2->xvel, pSprite, DAMAGE_TYPE_3, dmg); @@ -4242,9 +4355,9 @@ void ProcessTouchObjects(spritetype *pSprite, int nXSprite) int mass1 = dudeInfo[pSprite->type - kDudeBase].mass; int mass2 = dudeInfo[pSprite2->type - kDudeBase].mass; switch (pSprite2->type) { - case kGDXDudeUniversalCultist: - case kGDXGenDudeBurning: - mass2 = getDudeMassBySpriteSize(pSprite2); + case kCustomDude: + case kCustomDudeBurning: + mass2 = getSpriteMassBySize(pSprite2); break; } if (mass1 > mass2) { @@ -4258,14 +4371,14 @@ void ProcessTouchObjects(spritetype *pSprite, int nXSprite) } switch (pSprite->type) { - case kGDXDudeUniversalCultist: - case kGDXGenDudeBurning: + case kCustomDude: + case kCustomDudeBurning: { if (IsDudeSprite(pSprite2) && !IsPlayerSprite(pSprite2)) { - int mass1 = getDudeMassBySpriteSize(pSprite); - int mass2 = getDudeMassBySpriteSize(pSprite2); + int mass1 = getSpriteMassBySize(pSprite); + int mass2 = getSpriteMassBySize(pSprite2); - if (mass1 > mass2) { + if ((mass1 - mass2) >= mass2) { if ((pXSprite->target == pSprite2->xvel && !dudeIsMelee(pXSprite) && Chance(0x0500)) || pXSprite->target != pSprite2->xvel) actKickObject(pSprite, pSprite2); if (pSprite2->extra >= 0 && !isActive(pSprite2->xvel)) @@ -4318,9 +4431,9 @@ void ProcessTouchObjects(spritetype *pSprite, int nXSprite) int mass1 = dudeInfo[pSprite->type - kDudeBase].mass; int mass2 = dudeInfo[pSprite2->type - kDudeBase].mass; switch (pSprite2->type) { - case kGDXDudeUniversalCultist: - case kGDXGenDudeBurning: - mass2 = getDudeMassBySpriteSize(pSprite2); + case kCustomDude: + case kCustomDudeBurning: + mass2 = getSpriteMassBySize(pSprite2); break; } if (mass1 > mass2 && IsDudeSprite(pSprite2)) { @@ -4334,15 +4447,15 @@ void ProcessTouchObjects(spritetype *pSprite, int nXSprite) } switch (pSprite->type) { - case kGDXDudeUniversalCultist: - case kGDXGenDudeBurning: + case kCustomDude: + case kCustomDudeBurning: { if (IsDudeSprite(pSprite2) && !IsPlayerSprite(pSprite2)) { - int mass1 = getDudeMassBySpriteSize(pSprite); - int mass2 = getDudeMassBySpriteSize(pSprite2); + int mass1 = getSpriteMassBySize(pSprite); + int mass2 = getSpriteMassBySize(pSprite2); - if (mass1 > mass2) { - if (Chance((pXSprite->target == pSprite2->xvel) ? 0x1000 : 0x2000)) actKickObject(pSprite, pSprite2); + if ((mass1 - mass2) >= mass2) { + if (Chance((pXSprite->target == pSprite2->xvel) ? 0x0500 : 0x1000)) actKickObject(pSprite, pSprite2); if (pSprite2->extra >= 0 && !isActive(pSprite2->xvel)) aiActivateDude(pSprite2, &xsprite[pSprite2->extra]); } @@ -4426,6 +4539,35 @@ void ProcessTouchObjects(spritetype *pSprite, int nXSprite) } break; } + + // by NoOne: add more trigger statements for Touch flag + if (!VanillaMode()) { + + // Touch sprites + int nHSprite = -1; + if ((gSpriteHit[nXSprite].hit & 0xc000) == 0xc000) + nHSprite = gSpriteHit[nXSprite].hit & 0x3fff; + else if ((gSpriteHit[nXSprite].florhit & 0xc000) == 0xc000) + nHSprite = gSpriteHit[nXSprite].florhit & 0x3fff; + else if ((gSpriteHit[nXSprite].ceilhit & 0xc000) == 0xc000) + nHSprite = gSpriteHit[nXSprite].ceilhit & 0x3fff; + + if (nHSprite >= 0 && sprite[nHSprite].extra >= 0) { + XSPRITE* pXHSprite = &xsprite[sprite[nHSprite].extra]; + if (pXHSprite->Touch && !pXHSprite->isTriggered && (!pXHSprite->DudeLockout || IsPlayerSprite(pSprite))) + trTriggerSprite(nHSprite, pXHSprite, 33); + } + + // Touch walls + int nHWall = -1; + if ((gSpriteHit[nXSprite].hit & 0xc000) == 0x8000) { + if ((nHWall = gSpriteHit[nXSprite].hit & 0x3fff) >= 0 && wall[nHWall].extra >= 0) { + XWALL* pXHWall = &xwall[wall[nHWall].extra]; + if (pXHWall->triggerTouch && !pXHWall->isTriggered && (!pXHWall->dudeLockout || IsPlayerSprite(pSprite))) + trTriggerWall(nHWall, pXHWall, 52); + } + } + } } void actAirDrag(spritetype *pSprite, int a2) @@ -4960,6 +5102,10 @@ void MoveDude(spritetype *pSprite) case 239: actKillDude(pSprite->index, pSprite, DAMAGE_TYPE_0, 1000 << 4); break; + case kCustomDude: + evPost(nSprite, 3, 0, CALLBACK_ID_11); + if (!canSwim(pSprite)) actKillDude(pSprite->index, pSprite, DAMAGE_TYPE_0, 1000 << 4); + break; } } break; @@ -5425,8 +5571,8 @@ void actExplodeSprite(spritetype *pSprite) if (tSeq > 0) nSeq = tSeq; if (tSnd > 0) nSnd = tSnd; - //if (kExist(pXSPrite->data2, seq)) // GDX method to check if file exist in RFF - seqSpawn(nSeq, 3, nXSprite, -1); + if (gSysRes.Lookup(pXSPrite->data2, "SEQ")) + seqSpawn(nSeq, 3, nXSprite, -1); sfxPlay3DSound(pSprite, nSnd, -1, 0); } @@ -5497,6 +5643,130 @@ void actProcessSprites(void) { int nSprite; int nNextSprite; + + if (!VanillaMode()) { + + // by NoOne: process additional proximity sprites + if (gProxySpritesCount > 0) { + for (int i = 0; i < gProxySpritesCount; i++) { + if (sprite[gProxySpritesList[i]].extra < 0) continue; + + XSPRITE * pXProxSpr = &xsprite[sprite[gProxySpritesList[i]].extra]; + if (!pXProxSpr->Proximity || (!pXProxSpr->Interrutable && pXProxSpr->state != pXProxSpr->restState) || pXProxSpr->locked == 1 + || pXProxSpr->isTriggered) continue; // don't process locked or triggered sprites + + int x = sprite[gProxySpritesList[i]].x; int y = sprite[gProxySpritesList[i]].y; + int z = sprite[gProxySpritesList[i]].z; int index = sprite[gProxySpritesList[i]].xvel; + int sectnum = sprite[gProxySpritesList[i]].sectnum; + + if (!pXProxSpr->DudeLockout) { + + for (int nAffected = headspritestat[6]; nAffected >= 0; nAffected = nextspritestat[nAffected]) { + if ((sprite[nAffected].hitag & 32) || xsprite[sprite[nAffected].extra].health <= 0) continue; + else if (CheckProximity(&sprite[nAffected], x, y, z, sectnum, 96)) { + trTriggerSprite(index, pXProxSpr, 35); + break; + } + } + + } else { + + for (int a = connecthead; a >= 0; a = connectpoint2[a]) { + if (gPlayer[a].pXSprite->health > 0 && CheckProximity(gPlayer[a].pSprite, x, y, z, sectnum, 96)) { + trTriggerSprite(index, pXProxSpr, 35); + break; + } + } + + } + } + } + + // by NoOne: process sight sprites (for players only) + if (gSightSpritesCount > 0) { + for (int i = 0; i < gSightSpritesCount; i++) { + if (sprite[gSightSpritesList[i]].extra < 0) continue; + + XSPRITE * pXSightSpr = &xsprite[sprite[gSightSpritesList[i]].extra]; + if (!pXSightSpr->Sight || (!pXSightSpr->Interrutable && pXSightSpr->state != pXSightSpr->restState) || pXSightSpr->locked == 1 || + pXSightSpr->isTriggered) continue; // don't process locked or triggered sprites + + int x = sprite[gSightSpritesList[i]].x; int y = sprite[gSightSpritesList[i]].y; + int z = sprite[gSightSpritesList[i]].z; int index = sprite[gSightSpritesList[i]].xvel; + int sectnum = sprite[gSightSpritesList[i]].sectnum; + + for (int a = connecthead; a >= 0; a = connectpoint2[a]) { + spritetype* pPlaySprite = gPlayer[a].pSprite; + if (gPlayer[a].pXSprite->health > 0 && cansee(x, y, z, sectnum, pPlaySprite->x, pPlaySprite->y, pPlaySprite->z, pPlaySprite->sectnum)) { + trTriggerSprite(index, pXSightSpr, 34); + break; + } + } + } + } + + // by NoOne: process Debris sprites for movement + if (gPhysSpritesCount > 0) { + //System.err.println("PHYS COUNT: "+gPhysSpritesCount); + for (int i = 0; i < gPhysSpritesCount; i++) { + if (gPhysSpritesList[i] == -1) continue; + else if (sprite[gPhysSpritesList[i]].statnum == kStatFree || (sprite[gPhysSpritesList[i]].hitag & kHitagFree) != 0) { + gPhysSpritesList[i] = -1; + continue; + } + + XSPRITE* pXDebris = &xsprite[sprite[gPhysSpritesList[i]].extra]; + if (!(pXDebris->physAttr & kPhysMove) && !(pXDebris->physAttr & kPhysGravity)) { + gPhysSpritesList[i] = -1; + continue; + } + + 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) { + if (pXSector->Underwater) airVel <<= 6; + if (pXSector->panVel != 0) { + int top, bottom; + GetSpriteExtents(pDebris,&top,&bottom); + + if (getflorzofslope(pDebris->sectnum, pDebris->x, pDebris->y) <= bottom) + { + int angle = pXSector->panAngle; + int speed = 0; + if (pXSector->panAlways || pXSector->state || pXSector->busy) + { + speed = pXSector->panVel << 9; + if (!pXSector->panAlways && pXSector->busy) + speed = mulscale16(speed, pXSector->busy); + } + if (sector[pDebris->sectnum].floorstat & 64) + angle = (angle + GetWallAngle(sector[pDebris->sectnum].wallptr) + 512) & 2047; + int dx = mulscale30(speed, Cos(angle)); + int dy = mulscale30(speed, Sin(angle)); + xvel[pDebris->xvel] += dx; + yvel[pDebris->xvel] += dy; + } + } + } + + actAirDrag(pDebris, airVel); + + if (((pDebris->index >> 8) & 15) == (gFrame & 15) && (pXDebris->physAttr & kPhysGravity)) + pXDebris->physAttr |= kPhysFalling; + + if ((pXDebris->physAttr & 4) == 0 && xvel[pDebris->xvel] == 0 && yvel[pDebris->xvel] == 0 && + zvel[pDebris->xvel] == 0 && velFloor[pDebris->sectnum] == 0 && velCeil[pDebris->sectnum] == 0) + continue; + + debrisMove(i); + + } + } + } + for (nSprite = headspritestat[4]; nSprite >= 0; nSprite = nextspritestat[nSprite]) { spritetype *pSprite = &sprite[nSprite]; @@ -5514,21 +5784,8 @@ void actProcessSprites(void) pXSprite->burnTime = ClipLow(pXSprite->burnTime-4,0); actDamageSprite(actOwnerIdToSpriteId(pXSprite->burnSource), pSprite, DAMAGE_TYPE_1, 8); } - - // by NoOne: make Sight flag work and don't process sight flag for things which is locked or triggered - if (pXSprite->Sight && pXSprite->locked != 1 && pXSprite->isTriggered != true) { - for (int i = connecthead; i >= 0; i = connectpoint2[i]) { - PLAYER* pPlayer = &gPlayer[i]; int z = pPlayer->at6f - pPlayer->pSprite->z; - int hitCode = VectorScan(pPlayer->pSprite, 0, z, pPlayer->at1be.dx, pPlayer->at1be.dy, pPlayer->at1be.dz, 512000, 1); - if (hitCode != 3 || gHitInfo.hitsprite != pSprite->xvel) continue; - trTriggerSprite(nSprite, pXSprite, 34); - pXSprite->locked = 1; // lock it once triggered, so it can be unlocked again - - break; - } - } // by NoOne: don't process locked or 1-shot things for proximity - if (pXSprite->Proximity && pXSprite->locked != 1 && pXSprite->isTriggered != true) { + if (pXSprite->Proximity && (VanillaMode() || (pXSprite->locked != 1 && pXSprite->isTriggered != true))) { if (pSprite->type == 431) pXSprite->target = -1; for (int nSprite2 = headspritestat[6]; nSprite2 >= 0; nSprite2 = nNextSprite) { @@ -5539,6 +5796,11 @@ void actProcessSprites(void) XSPRITE *pXSprite2 = &xsprite[pSprite2->extra]; if ((unsigned int)pXSprite2->health > 0) { + + // by NoOne: allow dudeLockout for proximity flag + if (pSprite->type != 431 && pXSprite->DudeLockout && !IsPlayerSprite(pSprite2)) + continue; + int proxyDist = 96; if (pSprite->type == kGDXThingCustomDudeLifeLeech) proxyDist = 512; else if (pSprite->type == 431 && pXSprite->target == -1) @@ -5558,7 +5820,7 @@ void actProcessSprites(void) proxyDist = 512; } if (CheckProximity(pSprite2, pSprite->x, pSprite->y, pSprite->z, pSprite->sectnum, proxyDist)) { - + switch (pSprite->type) { case kGDXThingTNTProx: if (!IsPlayerSprite(pSprite2)) continue; @@ -5741,9 +6003,10 @@ void actProcessSprites(void) // or of Hidden Exploder. int radius = pXSprite->data4; if (pXSprite->data4 <= 0) - radius = pExplodeInfo->at3; + radius = pExplodeInfo->radius; GetClosestSpriteSectors(nSector, x, y, radius, gAffectedSectors, v24c, gAffectedXWalls); + for (int i = 0; i < kMaxXWalls; i++) { int nWall = gAffectedXWalls[i]; @@ -5752,6 +6015,7 @@ void actProcessSprites(void) XWALL *pXWall = &xwall[wall[nWall].extra]; trTriggerWall(nWall, pXWall, 51); } + for (int nSprite2 = headspritestat[6]; nSprite2 >= 0; nSprite2 = nextspritestat[nSprite2]) { spritetype *pDude = &sprite[nSprite2]; @@ -5766,8 +6030,8 @@ void actProcessSprites(void) pXSprite->target = 1; actDamageSprite(nOwner, pDude, DAMAGE_TYPE_0, (pExplodeInfo->at1+Random(pExplodeInfo->at2))<<4); } - if (pExplodeInfo->at7) - ConcussSprite(nOwner, pDude, x, y, z, pExplodeInfo->at7); + if (pExplodeInfo->dmgType) + ConcussSprite(nOwner, pDude, x, y, z, pExplodeInfo->dmgType); if (pExplodeInfo->atb) { dassert(pDude->extra > 0 && pDude->extra < kMaxXSprites); @@ -5779,6 +6043,7 @@ void actProcessSprites(void) } } } + for (int nSprite2 = headspritestat[4]; nSprite2 >= 0; nSprite2 = nextspritestat[nSprite2]) { spritetype *pThing = &sprite[nSprite2]; @@ -5791,8 +6056,8 @@ void actProcessSprites(void) XSPRITE *pXSprite2 = &xsprite[pThing->extra]; if (!pXSprite2->locked) { - if (pExplodeInfo->at7) - ConcussSprite(nOwner, pThing, x, y, z, pExplodeInfo->at7); + if (pExplodeInfo->dmgType) + ConcussSprite(nOwner, pThing, x, y, z, pExplodeInfo->dmgType); if (pExplodeInfo->atb) { dassert(pThing->extra > 0 && pThing->extra < kMaxXSprites); @@ -5805,6 +6070,20 @@ void actProcessSprites(void) } } } + + // by NoOne: add impulse for sprites from physics list + if (gPhysSpritesCount > 0 && pExplodeInfo->dmgType != 0 && pXSprite->data1 != 0) { + for (int i = 0; i < gPhysSpritesCount; i++) { + if (gPhysSpritesList[i] == -1) continue; + else if (sprite[gPhysSpritesList[i]].sectnum < 0 || (sprite[gPhysSpritesList[i]].hitag & kHitagFree) != 0) + continue; + + spritetype* pDebris = &sprite[gPhysSpritesList[i]]; + if (!TestBitString(v24c, pDebris->sectnum) || !CheckProximity(pDebris, x, y, z, nSector, radius)) continue; + else debrisConcuss(nOwner, i, x, y, z, pExplodeInfo->dmgType); + } + } + for (int p = connecthead; p >= 0; p = connectpoint2[p]) { spritetype *pSprite2 = gPlayer[p].pSprite; @@ -5818,7 +6097,7 @@ void actProcessSprites(void) // By NoOne: if data4 > 0, do not remove explosion. This can be useful when designer wants put explosion generator in map manually // via sprite statnum 2. - if (!(pSprite->hitag & kHitagExtBit)) { + if (!(pSprite->hitag & kModernTypeFlag1)) { pXSprite->data1 = ClipLow(pXSprite->data1 - 4, 0); pXSprite->data2 = ClipLow(pXSprite->data2 - 4, 0); pXSprite->data3 = ClipLow(pXSprite->data3 - 4, 0); @@ -5827,8 +6106,8 @@ void actProcessSprites(void) if (pXSprite->data1 == 0 && pXSprite->data2 == 0 && pXSprite->data3 == 0 && seqGetStatus(3, nXSprite) < 0) actPostSprite(nSprite, 1024); } - for (nSprite = headspritestat[11]; nSprite >= 0; nSprite = nextspritestat[nSprite]) - { + + for (nSprite = headspritestat[11]; nSprite >= 0; nSprite = nextspritestat[nSprite]) { spritetype *pSprite = &sprite[nSprite]; if (pSprite->hitag & 32) continue; @@ -5896,26 +6175,48 @@ void actProcessSprites(void) } // By NoOne: handle incarnations of custom dude - if (pSprite->type == kGDXDudeUniversalCultist && pXSprite->health <= 0 && seqGetStatus(3, nXSprite) < 0) { + if (pSprite->type == kCustomDude && pXSprite->txID > 0 && pXSprite->health <= 0 && seqGetStatus(3, nXSprite) < 0) { XSPRITE* pXIncarnation = getNextIncarnation(pXSprite); if (pXIncarnation != NULL) { spritetype* pIncarnation = &sprite[pXIncarnation->reference]; + pXSprite->key = pXSprite->dropMsg = pXSprite->locked = 0; - pSprite->type = pIncarnation->type; + // save incarnation's going on and off options + bool triggerOn = pXIncarnation->triggerOn; + bool triggerOff = pXIncarnation->triggerOff; + + // then remove it from incarnation so it will not send the commands + pXIncarnation->triggerOn = false; + pXIncarnation->triggerOff = false; + + // trigger dude death before transform + trTriggerSprite(nSprite, pXSprite, COMMAND_ID_0); + + pSprite->lotag = pIncarnation->lotag; + pSprite->hitag = pIncarnation->hitag; pSprite->pal = pIncarnation->pal; pSprite->shade = pIncarnation->shade; + pSprite->clipdist = pIncarnation->clipdist; + pSprite->xrepeat = pIncarnation->xrepeat; + pSprite->yrepeat = pIncarnation->yrepeat; pXSprite->txID = pXIncarnation->txID; pXSprite->command = pXIncarnation->command; - pXSprite->triggerOn = pXIncarnation->triggerOn; - pXSprite->triggerOff = pXIncarnation->triggerOff; + pXSprite->triggerOn = triggerOn; + pXSprite->triggerOff = triggerOff; + pXSprite->busyTime = pXIncarnation->busyTime; + pXSprite->waitTime = pXIncarnation->waitTime; pXSprite->burnTime = 0; pXSprite->burnSource = -1; pXSprite->data1 = pXIncarnation->data1; - pXSprite->data2 = pXIncarnation->data2; - pXSprite->data3 = pXIncarnation->data3; + short oldData2 = pXSprite->data2; pXSprite->data2 = pXIncarnation->data2; // seq new seqId and save old one. + + // if incarnation is active dude, it's sndStartId will be stored in sysData1, otherwise it will be data3 + if (pIncarnation->statnum == 6 && pIncarnation->type == kCustomDude) pXSprite->sysData1 = pXIncarnation->sysData1; + else pXIncarnation->data3; + pXSprite->data4 = pXIncarnation->data4; pXSprite->dudeGuard = pXIncarnation->dudeGuard; @@ -5923,22 +6224,64 @@ void actProcessSprites(void) pXSprite->dudeAmbush = pXIncarnation->dudeAmbush; pXSprite->dudeFlag4 = pXIncarnation->dudeFlag4; - pXSprite->busyTime = pXIncarnation->busyTime; - aiInitSprite(pSprite); + pXSprite->dropMsg = pXIncarnation->dropMsg; + pXSprite->key = pXIncarnation->key; + + pXSprite->locked = pXIncarnation->locked; + pXSprite->Decoupled = pXIncarnation->Decoupled; + + // clear drop items of the incarnation + pXIncarnation->key = pXIncarnation->dropMsg = 0; + + // set hp + if (pXSprite->data4 <= 0) pXSprite->health = dudeInfo[pSprite->type - kDudeBase].startHealth << 4; + else pXSprite->health = ClipRange(pXSprite->data4 << 4, 1, 65535); + + int seqId = dudeInfo[pSprite->type - kDudeBase].seqStartID; switch (pSprite->type) { - case kGDXDudeUniversalCultist: - case kGDXGenDudeBurning: - if (pXSprite->data2 > 0) seqSpawn(pXSprite->data2, 3, nXSprite, -1); - else seqSpawn(dudeInfo[pSprite->type - kDudeBase].seqStartID, 3, nXSprite, -1); + case 225: // fake dude + case 226: // fake dude break; + case kCustomDude: + case kCustomDudeBurning: + seqId = getSeqStartId(pXSprite); + if (seqId != oldData2) + getSpriteMassBySize(pSprite); // create or refresh mass cache + fallthrough__; // go below default: - seqSpawn(dudeInfo[pSprite->type - kDudeBase].seqStartID, 3, nXSprite, -1); + seqSpawn(seqId, 3, nXSprite, -1); + + // save target + int target = pXSprite->target; + + // re-init sprite + aiInitSprite(pSprite); + + // try to restore target + if (target == -1) aiSetTarget(pXSprite, pSprite->x, pSprite->y, pSprite->z); + else aiSetTarget(pXSprite, target); + + // finally activate it + aiActivateDude(pSprite, pXSprite); + break; } - if (pXSprite->data4 > 0) pXSprite->health = pXSprite->data4; - else pXSprite->health = dudeInfo[pSprite->type - kDudeBase].startHealth << 4; - aiActivateDude(pSprite, pXSprite); + // remove the incarnation in case if non-locked + if (pXIncarnation->locked == 0) { + pXIncarnation->txID = pIncarnation->lotag = 0; + actPostSprite(pIncarnation->xvel, kStatFree); + // or restore triggerOn and off options + } else { + pXIncarnation->triggerOn = triggerOn; + pXIncarnation->triggerOff = triggerOff; + } + + } else { + + // just trigger dude death + trTriggerSprite(nSprite, pXSprite, COMMAND_ID_0); + } } @@ -6157,27 +6500,28 @@ spritetype *actSpawnDude(spritetype *pSource, short nType, int a3, int a4) // By NoOne: add a way to inherit some values of spawner type 18 by dude. // This way designer can count enemies via switches and do many other interesting things. + if (pSource->hitag & kModernTypeFlag1) { + switch (pSource->type) { // allow inheriting only for selected source types + case 18: + //inherit pal? + if (pSprite2->pal <= 0) pSprite2->pal = pSource->pal; - // oops, forget to check for source type previously - if ((pSource->hitag & kHitagExtBit) != 0 && pSource->type == 18) { - - //inherit pal? - if (pSprite2->pal <= 0) pSprite2->pal = pSource->pal; + // inherit spawn sprite trigger settings, so designer can count monsters. + pXSprite2->txID = pXSource->txID; + pXSprite2->command = pXSource->command; + pXSprite2->triggerOn = pXSource->triggerOn; + pXSprite2->triggerOff = pXSource->triggerOff; - // inherit spawn sprite trigger settings, so designer can count monsters. - pXSprite2->txID = pXSource->txID; - pXSprite2->command = pXSource->command; - pXSprite2->triggerOn = pXSource->triggerOn; - pXSprite2->triggerOff = pXSource->triggerOff; + // inherit drop items + pXSprite2->dropMsg = pXSource->dropMsg; - // inherit drop items - pXSprite2->dropMsg = pXSource->dropMsg; - - // inherit dude flags - pXSprite2->dudeDeaf = pXSource->dudeDeaf; - pXSprite2->dudeGuard = pXSource->dudeGuard; - pXSprite2->dudeAmbush = pXSource->dudeAmbush; - pXSprite2->dudeFlag4 = pXSource->dudeFlag4; + // inherit dude flags + pXSprite2->dudeDeaf = pXSource->dudeDeaf; + pXSprite2->dudeGuard = pXSource->dudeGuard; + pXSprite2->dudeAmbush = pXSource->dudeAmbush; + pXSprite2->dudeFlag4 = pXSource->dudeFlag4; + break; + } } aiInitSprite(pSprite2); @@ -6323,6 +6667,7 @@ spritetype * actFireThing(spritetype *pSprite, int a2, int a3, int a4, int thing spritetype* actFireMissile(spritetype *pSprite, int a2, int a3, int a4, int a5, int a6, int nType) { + dassert(nType >= kMissileBase && nType < kMissileMax); char v4 = 0; int nSprite = pSprite->index; @@ -6369,7 +6714,20 @@ spritetype* actFireMissile(spritetype *pSprite, int a2, int a3, int a4, int a5, dassert(nXSprite > 0 && nXSprite < kMaxXSprites); xsprite[nXSprite].target = -1; evPost(nMissile, 3, 600, CALLBACK_ID_1); - switch (nType) + + actBuildMissile(pMissile, nXSprite, nSprite); + + if (v4) + { + actImpactMissile(pMissile, hit); + pMissile = NULL; + } + return pMissile; +} + +void actBuildMissile(spritetype* pMissile, int nXSprite, int nSprite) { + int nMissile = pMissile->index; + switch (pMissile->type) { case 315: evPost(nMissile, 3, 0, CALLBACK_ID_0); @@ -6400,9 +6758,9 @@ spritetype* actFireMissile(spritetype *pSprite, int a2, int a3, int a4, int a5, break; case 308: seqSpawn(27, 3, nXSprite, -1); - xvel[nMissile] += xvel[nSprite]/2+Random2(0x11111); - yvel[nMissile] += yvel[nSprite]/2+Random2(0x11111); - zvel[nMissile] += zvel[nSprite]/2+Random2(0x11111); + xvel[nMissile] += xvel[nSprite] / 2 + Random2(0x11111); + yvel[nMissile] += yvel[nSprite] / 2 + Random2(0x11111); + zvel[nMissile] += zvel[nSprite] / 2 + Random2(0x11111); break; case 313: seqSpawn(61, 3, nXSprite, dword_2192E0); @@ -6410,18 +6768,18 @@ spritetype* actFireMissile(spritetype *pSprite, int a2, int a3, int a4, int a5, break; case 314: seqSpawn(23, 3, nXSprite, dword_2192D8); - xvel[nMissile] += xvel[nSprite]/2+Random2(0x11111); - yvel[nMissile] += yvel[nSprite]/2+Random2(0x11111); - zvel[nMissile] += zvel[nSprite]/2+Random2(0x11111); + xvel[nMissile] += xvel[nSprite] / 2 + Random2(0x11111); + yvel[nMissile] += yvel[nSprite] / 2 + Random2(0x11111); + zvel[nMissile] += zvel[nSprite] / 2 + Random2(0x11111); break; case 304: if (Chance(0x8000)) seqSpawn(0, 3, nXSprite, -1); else seqSpawn(1, 3, nXSprite, -1); - xvel[nMissile] += xvel[nSprite]+Random2(0x11111); - yvel[nMissile] += yvel[nSprite]+Random2(0x11111); - zvel[nMissile] += zvel[nSprite]+Random2(0x11111); + xvel[nMissile] += xvel[nSprite] + Random2(0x11111); + yvel[nMissile] += yvel[nSprite] + Random2(0x11111); + zvel[nMissile] += zvel[nSprite] + Random2(0x11111); break; case 303: evPost(nMissile, 3, 30, CALLBACK_ID_2); @@ -6439,12 +6797,6 @@ spritetype* actFireMissile(spritetype *pSprite, int a2, int a3, int a4, int a5, sfxPlay3DSound(pMissile, 252, 0, 0); break; } - if (v4) - { - actImpactMissile(pMissile, hit); - pMissile = NULL; - } - return pMissile; } int actGetRespawnTime(spritetype *pSprite) @@ -6687,9 +7039,9 @@ void actFireVector(spritetype *pShooter, int a2, int a3, int a4, int a5, int a6, if (IsDudeSprite(pSprite)) { switch (pSprite->lotag) { - case kGDXDudeUniversalCultist: - case kGDXGenDudeBurning: - t = getDudeMassBySpriteSize(pSprite); + case kCustomDude: + case kCustomDudeBurning: + t = getSpriteMassBySize(pSprite); break; } } @@ -6748,6 +7100,26 @@ void actFireVector(spritetype *pShooter, int a2, int a3, int a4, int a5, int a6, if (Chance(pVectorData->at19)) fxSpawnBlood(pSprite, pVectorData->at1<<4); } + + // by NoOne: add impulse for sprites from physics list + if (gPhysSpritesCount > 0 && pVectorData->at5) { + int nIndex = isDebris(pSprite->index); + if (nIndex != -1 && (xsprite[pSprite->extra].physAttr & kPhysDebrisVector)) { + int impulse = divscale(pVectorData->at5, ClipLow(gSpriteMass[pSprite->extra].mass, 10), 6); + xvel[nSprite] += mulscale16(a4, impulse); + yvel[nSprite] += mulscale16(a5, impulse); + zvel[nSprite] += mulscale16(a6, impulse); + + if (pVectorData->at11 != 0) { + if (!xsprite[nXSprite].burnTime) evPost(nSprite, 3, 0, CALLBACK_ID_0); + actBurnSprite(actSpriteIdToOwnerId(nShooter), &xsprite[nXSprite], pVectorData->at11); + } + + if (pSprite->index >= kThingBase && pSprite->index < kThingMax) + actPostSprite(pSprite->index, 4); // if it was a thing, return it's statnum back + } + } + break; } } @@ -6958,7 +7330,7 @@ void ActorLoadSave::Load(void) Read(gAffectedXWalls, sizeof(gAffectedXWalls)); Read(&gPostCount, sizeof(gPostCount)); Read(gPost, sizeof(gPost)); - actInit(); + actInit(true); } void ActorLoadSave::Save(void) @@ -6980,21 +7352,25 @@ void ActorLoadSaveConstruct(void) // By NoOne: The following functions required for random event features //------------------------- - int GetDataVal(spritetype* pSprite, int data) { - XSPRITE* pXSprite = &xsprite[pSprite->extra]; - int rData[4]; - - rData[0] = pXSprite->data1; rData[2] = pXSprite->data3; - rData[1] = pXSprite->data2; rData[3] = pXSprite->data4; - - return rData[data]; + if (pSprite->extra >= 0) { + switch (data) { + case 0: + return xsprite[pSprite->extra].data1; + case 1: + return xsprite[pSprite->extra].data2; + case 2: + return xsprite[pSprite->extra].data3; + case 3: + return xsprite[pSprite->extra].data4; + } + } + return -1; } std::default_random_engine rng; -int my_random(int a, int b) -{ +int my_random(int a, int b) { std::uniform_int_distribution dist_a_b(a, b); return dist_a_b(rng); @@ -7039,20 +7415,20 @@ int GetRandDataVal(int *rData, spritetype* pSprite) { while (maxRetries > 0) { // use true random only for single player mode - if (gGameOptions.nGameType == 0 && !VanillaMode() && !DemoRecordStatus()) { - rng.seed(std::random_device()()); - random = my_random(0, 4); // otherwise use Blood's default one. In the future it maybe possible to make // host send info to clients about what was generated. - } else { - random = Random(3); + + if (gGameOptions.nGameType != 0 || VanillaMode() || DemoRecordStatus()) random = Random(3); + else { + rng.seed(std::random_device()()); + random = my_random(0, 4); } - if (rData[random] > 0) return rData[random]; - maxRetries--; + if (rData[random] > 0) return rData[random]; + maxRetries--; } - // if nothing, get first found data value from top + // if nothing, get first found data value from top return rData[b]; } @@ -7070,26 +7446,31 @@ spritetype* DropRandomPickupObject(spritetype* pSprite, short prevItem) { rData[i] = 0; int maxRetries = 9; - while ((selected = GetRandDataVal(rData, NULL)) == prevItem) if (maxRetries <= 0) break; + while ((selected = GetRandDataVal(rData, NULL)) == prevItem) if (maxRetries-- <= 0) break; if (selected > 0) { spritetype* pSource = pSprite; XSPRITE* pXSource = &xsprite[pSource->extra]; pSprite2 = actDropObject(pSprite, selected); - pXSource->dropMsg = pSprite2->lotag; // store dropped item lotag in dropMsg - - if ((pSource->hitag & kHitagExtBit) != 0) - { - int nXSprite2 = pSprite2->extra; - if (nXSprite2 <= 0) - nXSprite2 = dbInsertXSprite(pSprite2->index); - XSPRITE *pXSprite2 = &xsprite[nXSprite2]; + if (pSprite2 != NULL) { + + pXSource->dropMsg = pSprite2->lotag; // store dropped item lotag in dropMsg + pSprite2->x = pSource->x; + pSprite2->y = pSource->y; + pSprite2->z = pSource->z; - // inherit spawn sprite trigger settings, so designer can send command when item picked up. - pXSprite2->txID = pXSource->txID; - pXSprite2->command = pXSource->command; - pXSprite2->triggerOn = pXSource->triggerOn; - pXSprite2->triggerOff = pXSource->triggerOff; + if ((pSource->hitag & kModernTypeFlag1) && (pXSource->txID > 0 || (pXSource->txID != 3 && pXSource->lockMsg > 0)) && + dbInsertXSprite(pSprite2->xvel) > 0) { + + XSPRITE * pXSprite2 = &xsprite[pSprite2->extra]; - pXSprite2->Pickup = true; + // inherit spawn sprite trigger settings, so designer can send command when item picked up. + pXSprite2->txID = pXSource->txID; + pXSprite2->command = pXSource->command; + pXSprite2->triggerOn = pXSource->triggerOn; + pXSprite2->triggerOff = pXSource->triggerOff; + + pXSprite2->Pickup = true; + + } } } @@ -7147,7 +7528,7 @@ spritetype* actSpawnCustomDude(spritetype* pSprite, int nDist) { spritetype* pSource = pSprite; XSPRITE* pXSource = &xsprite[pSource->extra]; spritetype* pDude = actSpawnSprite(pSprite,6); XSPRITE* pXDude = &xsprite[pDude->extra]; - int x, y, z = pSprite->z, nAngle = pSprite->ang, nType = kGDXDudeUniversalCultist; + int x, y, z = pSprite->z, nAngle = pSprite->ang, nType = kCustomDude; if (nDist > 0) { x = pSprite->x + mulscale30r(Cos(nAngle), nDist); @@ -7162,75 +7543,86 @@ spritetype* actSpawnCustomDude(spritetype* pSprite, int nDist) { vec3_t pos = { x, y, z }; setsprite(pDude->index, &pos); pDude->cstat |= 0x1101; pDude->clipdist = dudeInfo[nType - kDudeBase].clipdist; - // inherit weapon and sound settings. + // inherit weapon, seq and sound settings. pXDude->data1 = pXSource->data1; - pXDude->data3 = pXSource->data3; + pXDude->data2 = pXSource->data2; + pXDude->sysData1 = pXSource->data3; // move sndStartId from data3 to sysData1 + pXDude->data3 = 0; + + // spawn seq + seqSpawn(getSeqStartId(pXDude), 3, pDude->extra, -1); // inherit movement speed. pXDude->busyTime = pXSource->busyTime; + // inherit clipdist? + if (pSource->clipdist > 0) pDude->clipdist = pSource->clipdist; + // inherit custom hp settings - if (pXSource->data4 > 0) pXDude->health = pXSource->data4; - else pXDude->health = dudeInfo[nType - kDudeBase].startHealth << 4; + if (pXSource->data4 <= 0) pXDude->health = dudeInfo[nType].startHealth << 4; + else pXDude->health = ClipRange(pXSource->data4 << 4, 1, 65535); - // inherit seq settings - int seqId = dudeInfo[nType - kDudeBase].seqStartID; - if (pXSource->data2 > 0) seqId = pXSource->data2; - pXDude->data2 = seqId; + if (pSource->hitag & kModernTypeFlag1) { + switch (pSource->type) { + case kGDXCustomDudeSpawn: + //inherit pal? + if (pDude->pal <= 0) pDude->pal = pSource->pal; - if (gSysRes.Lookup(seqId,"SEQ")) - seqSpawn(seqId, 3, pDude->extra, -1); + // inherit spawn sprite trigger settings, so designer can count monsters. + pXDude->txID = pXSource->txID; + pXDude->command = pXSource->command; + pXDude->triggerOn = pXSource->triggerOn; + pXDude->triggerOff = pXSource->triggerOff; - if ((pSource->hitag & kHitagExtBit) != 0) { - //inherit pal? - if (pDude->pal <= 0) pDude->pal = pSource->pal; + // inherit drop items + pXDude->dropMsg = pXSource->dropMsg; - // inherit spawn sprite trigger settings, so designer can count monsters. - pXDude->txID = pXSource->txID; - pXDude->command = pXSource->command; - pXDude->triggerOn = pXSource->triggerOn; - pXDude->triggerOff = pXSource->triggerOff; + // inherit required key so it can be dropped + pXDude->key = pXSource->key; - // inherit drop items - pXDude->dropMsg = pXSource->dropMsg; - - // inherit dude flags - pXDude->dudeDeaf = pXSource->dudeDeaf; - pXDude->dudeGuard = pXSource->dudeGuard; - pXDude->dudeAmbush = pXSource->dudeAmbush; - pXDude->dudeFlag4 = pXSource->dudeFlag4; + // inherit dude flags + pXDude->dudeDeaf = pXSource->dudeDeaf; + pXDude->dudeGuard = pXSource->dudeGuard; + pXDude->dudeAmbush = pXSource->dudeAmbush; + pXDude->dudeFlag4 = pXSource->dudeFlag4; + break; + } } aiInitSprite(pDude); return pDude; } -int getDudeMassBySpriteSize(spritetype* pSprite) { - int mass = 0; int minMass = 5; +int getSpriteMassBySize(spritetype* pSprite) { + int mass = 0; int seqId = -1; Seq* pSeq = NULL; if (IsDudeSprite(pSprite)) { - int picnum = pSprite->picnum; Seq* pSeq = NULL; - int seqStartId = dudeInfo[pSprite->lotag - kDudeBase].seqStartID; + switch (pSprite->lotag) { - case kGDXDudeUniversalCultist: - case kGDXGenDudeBurning: - seqStartId = xsprite[pSprite->extra].data2; - break; + case 225: // fake dude, no seq + break; + case kCustomDude: + case kCustomDudeBurning: + seqId = xsprite[pSprite->extra].data2; + break; + default: + seqId = dudeInfo[pSprite->lotag - kDudeBase].seqStartID; + break; } + } else if (pSprite->extra >= 0) { - DICTNODE* hSeq = gSysRes.Lookup(seqStartId, "SEQ"); - pSeq = (Seq*)gSysRes.Load(hSeq); - if (pSeq != NULL) - picnum = seqGetTile(&pSeq->frames[0]); + seqId = seqGetID(3, pSprite->extra); - int clipDist = pSprite->clipdist; - if (clipDist <= 0) - clipDist = dudeInfo[pSprite->lotag - kDudeBase].clipdist; + } + + SPRITEMASS* cached = &gSpriteMass[pSprite->extra]; + if (((seqId >= 0 && seqId == cached->seqId) || pSprite->picnum == cached->picnum) && pSprite->xrepeat == cached->xrepeat && + pSprite->yrepeat == cached->yrepeat && pSprite->clipdist == cached->clipdist) { + return cached->mass; + } - int xrepeat = pSprite->xrepeat; - int x = tilesiz[picnum].x; - if (xrepeat > 64) x += ((xrepeat - 64) * 2); - else if (xrepeat < 64) x -= ((64 - xrepeat) * 2); + short picnum = pSprite->picnum; + short massDiv = 30; short addMul = 2; short subMul = 2; if (seqId >= 0) { DICTNODE* hSeq = gSysRes.Lookup(seqId, "SEQ"); @@ -7243,15 +7635,291 @@ int getDudeMassBySpriteSize(spritetype* pSprite) { picnum = pSprite->picnum; } - mass = ((x + y) * clipDist) / 25; - //if ((mass+=(x+y)) > 200) mass+=((mass - 200)*16); + int clipDist = ClipRange(pSprite->clipdist, 1, 255); + short x = tilesiz[picnum].x; short y = tilesiz[picnum].y; + short xrepeat = pSprite->xrepeat; short yrepeat = pSprite->yrepeat; + + // take surface type into account + switch (tileGetSurfType(pSprite->xvel + 0xc000)) { + case 1: massDiv = 16; break; // stone + case 2: massDiv = 18; break; // metal + case 3: massDiv = 21; break; // wood + case 4: massDiv = 25; break; // flesh + case 5: massDiv = 28; break; // water + case 6: massDiv = 26; break; // dirt + case 7: massDiv = 27; break; // clay + case 8: massDiv = 35; break; // snow + case 9: massDiv = 22; break; // ice + case 10: massDiv = 37; break; // leaves + case 11: massDiv = 33; break; // cloth + case 12: massDiv = 36; break; // plant + case 13: massDiv = 24; break; // goo + case 14: massDiv = 23; break; // lava } - if (mass < minMass) return minMass; - else if (mass > 65000) return 65000; - return mass; + mass = ((x + y) * (clipDist / 2)) / massDiv; + + if (xrepeat > 64) mass += ((xrepeat - 64) * addMul); + else if (xrepeat < 64 && mass > 0) { + for (int i = 64 - xrepeat; i > 0; i--) { + if ((mass -= subMul) <= 100 && subMul-- <= 1) { + mass -= i; + break; + } + } + } + + if (yrepeat > 64) mass += ((yrepeat - 64) * addMul); + else if (yrepeat < 64 && mass > 0) { + for (int i = 64 - yrepeat; i > 0; i--) { + if ((mass -= subMul) <= 100 && subMul-- <= 1) { + mass -= i; + break; + } + } + } + + if (mass <= 0) cached->mass = 1 + Random(10); + else cached->mass = ClipRange(mass, 1, 65535); + + cached->airVel = ClipRange(400 - cached->mass, 32, 400); + cached->fraction = ClipRange(60000 - (cached->mass << 7), 8192, 60000); + + cached->xrepeat = pSprite->xrepeat; cached->yrepeat = pSprite->yrepeat; + cached->picnum = pSprite->picnum; cached->seqId = seqId; + cached->clipdist = pSprite->clipdist; + + return cached->mass; } +int isDebris(int nSprite) { + if (sprite[nSprite].extra < 0 || xsprite[sprite[nSprite].extra].physAttr == 0) + return -1; + + for (int i = 0; i < gPhysSpritesCount; i++) { + if (gPhysSpritesList[i] != nSprite) continue; + return i; + } + + return -1; +} + +int debrisGetFreeIndex(void) { + for (int i = 0; i < kMaxSuperXSprites; i++) { + if (gPhysSpritesList[i] == -1 || sprite[gPhysSpritesList[i]].statnum == kStatFree) return i; + else if ((sprite[gPhysSpritesList[i]].hitag & kHitagFree) || sprite[gPhysSpritesList[i]].extra < 0) return i; + else if (xsprite[sprite[gPhysSpritesList[i]].extra].physAttr == 0) return i; + } + + return -1; +} + +void debrisConcuss(int nOwner, int listIndex, int x, int y, int z, int dmg) { + spritetype* pSprite = (gPhysSpritesList[listIndex] >= 0) ? &sprite[gPhysSpritesList[listIndex]] : NULL; + if (pSprite != NULL && pSprite->extra >= 0 && pSprite->extra < kMaxXSprites) { + int dx = pSprite->x - x; int dy = pSprite->y - y; int dz = (pSprite->z - z) >> 4; + dmg = scale(0x40000, dmg, 0x40000 + dx * dx + dy * dy + dz * dz); + + int size = (tilesiz[pSprite->picnum].x * pSprite->xrepeat * tilesiz[pSprite->picnum].y * pSprite->yrepeat) >> 1; + if (xsprite[pSprite->extra].physAttr & kPhysDebrisExplode) { + if (gSpriteMass[pSprite->extra].mass > 0) { + int t = scale(dmg, size, gSpriteMass[pSprite->extra].mass); + + xvel[pSprite->xvel] += mulscale16(t, dx); + yvel[pSprite->xvel] += mulscale16(t, dy); + zvel[pSprite->xvel] += mulscale16(t, dz); + } + } + + if (pSprite->index >= kThingBase && pSprite->index < kThingMax) + actPostSprite(pSprite->index, 4); // if it was a thing, return it's statnum back + + actDamageSprite(nOwner, pSprite, DAMAGE_TYPE_3, dmg); + return; + } +} + +void debrisMove(int listIndex) { + if (!(sprite[gPhysSpritesList[listIndex]].extra > 0 && sprite[gPhysSpritesList[listIndex]].extra < kMaxXSprites)) { + gPhysSpritesList[listIndex] = -1; + return; + } + else if (!(sprite[gPhysSpritesList[listIndex]].sectnum >= 0 && sprite[gPhysSpritesList[listIndex]].sectnum < kMaxSectors)) { + gPhysSpritesList[listIndex] = -1; + return; + } + + int nSprite = gPhysSpritesList[listIndex]; + int nXSprite = sprite[nSprite].extra; XSPRITE* pXDebris = &xsprite[nXSprite]; + spritetype* pSprite = &sprite[nSprite]; int nSector = pSprite->sectnum; + + int top, bottom; GetSpriteExtents(pSprite, &top, &bottom); + + int moveHit = 0; + int floorDist = (bottom - pSprite->z) / 4; + int ceilDist = (pSprite->z - top) / 4; + int clipDist = pSprite->clipdist << 2; + + int tmpFraction = gSpriteMass[pSprite->extra].fraction; + if (sector[nSector].extra >= 0 && xsector[sector[nSector].extra].Underwater) + tmpFraction >>= 1; + + if (xvel[pSprite->xvel] != 0 || yvel[pSprite->xvel] != 0) { + + short oldcstat = pSprite->cstat; + pSprite->cstat &= ~(CSTAT_SPRITE_BLOCK | CSTAT_SPRITE_BLOCK_HITSCAN); + + moveHit = gSpriteHit[nXSprite].hit = ClipMove((int*)& pSprite->x, (int*)& pSprite->y, (int*)& pSprite->z, &nSector, xvel[nSprite] >> 12, + yvel[nSprite] >> 12, pSprite->clipdist << 2, (pSprite->z - top) / 4, (bottom - pSprite->z) / 4, CLIPMASK0); + + pSprite->cstat = oldcstat; + + dassert(nSector >= 0); + + if (pSprite->sectnum != nSector) { + dassert(nSector >= 0 && nSector < kMaxSectors); + ChangeSpriteSect(nSprite, nSector); + } + + if ((gSpriteHit[nXSprite].hit & 0xc000) == 0x8000) { + int nHitWall = gSpriteHit[nXSprite].hit & 0x3fff; + actWallBounceVector((int*)& xvel[nSprite], (int*)& yvel[nSprite], nHitWall, tmpFraction); + } + + } + else { + dassert(nSector >= 0 && nSector < kMaxSectors); + FindSector(pSprite->x, pSprite->y, pSprite->z, &nSector); + } + + if (zvel[nSprite]) + pSprite->z += zvel[nSprite] >> 8; + + int ceilZ, ceilHit, floorZ, floorHit; + GetZRange(pSprite, &ceilZ, &ceilHit, &floorZ, &floorHit, pSprite->clipdist << 2, CLIPMASK0); + GetSpriteExtents(pSprite, &top, &bottom); + + if ((pXDebris->physAttr & kPhysGravity) && bottom < floorZ) { + pSprite->z += 455; + zvel[nSprite] += 58254; + } + int warp = CheckLink(pSprite); + if (warp != 0) { + GetZRange(pSprite, &ceilZ, &ceilHit, &floorZ, &floorHit, pSprite->clipdist << 2, CLIPMASK0); + if (!(pSprite->cstat & CSTAT_SPRITE_INVISIBLE)) { + switch (warp) { + case kMarkerUpWater: + case kMarkerUpGoo: + long pitch = (150000 - (gSpriteMass[pSprite->extra].mass << 9)) + Random3(8192); + sfxPlay3DSoundCP(pSprite, 720, -1, 0, pitch, 75 - Random(40)); + + if (sector[pSprite->sectnum].extra < 0 || !xsector[sector[pSprite->sectnum].extra].Underwater) + evKill(pSprite->xvel, 3, CALLBACK_ID_11); + else { + if (Chance(0x8000)) + evPost(pSprite->xvel, 3, 0, CALLBACK_ID_11); + + for (int i = 2; i <= 5; i++) { + if (Chance(0x3000 * i)) + evPost(pSprite->xvel, 3, 0, CALLBACK_ID_11); + } + } + break; + } + } + } + + GetSpriteExtents(pSprite, &top, &bottom); + + if ((floorHit & 0xe000) == 0xc000) { + if ((sprite[floorHit & 0x1fff].cstat & 0x30) == 0x20) + if (klabs(bottom - floorZ) < 1024) floorZ -= 1024; + } + + if (bottom >= floorZ) { + + gSpriteHit[nXSprite].florhit = floorHit; + pSprite->z += floorZ - bottom; + int v20 = zvel[nSprite] - velFloor[pSprite->sectnum]; + if (v20 > 0) { + + pXDebris->physAttr |= kPhysFalling; + int vax = actFloorBounceVector((int*)& xvel[nSprite], (int*)& yvel[nSprite], (int*)& v20, pSprite->sectnum, tmpFraction); + zvel[nSprite] = v20; + + if (velFloor[pSprite->sectnum] == 0 && klabs(zvel[nSprite]) < 0x10000) { + zvel[nSprite] = 0; + pXDebris->physAttr &= ~kPhysFalling; + } + + moveHit = 0x4000 | nSector; + + } + else if (zvel[nSprite] == 0) + pXDebris->physAttr &= ~kPhysFalling; + + } + else { + + gSpriteHit[nXSprite].florhit = 0; + if (pXDebris->physAttr & kPhysGravity) + pXDebris->physAttr |= kPhysFalling; + } + + if (top <= ceilZ) { + + gSpriteHit[nXSprite].ceilhit = ceilHit; + pSprite->z += ClipLow(ceilZ - top, 0); + if (zvel[nSprite] < 0) + { + xvel[nSprite] = mulscale16(xvel[nSprite], 0xc000); + yvel[nSprite] = mulscale16(yvel[nSprite], 0xc000); + zvel[nSprite] = mulscale16(-zvel[nSprite], 0x4000); + } + + } + else { + + gSpriteHit[nXSprite].ceilhit = 0; + + } + + if (bottom >= floorZ) { + int nVel = approxDist(xvel[nSprite], yvel[nSprite]); + int nVelClipped = ClipHigh(nVel, 0x11111); + + if ((floorHit & 0xc000) == 0xc000) { + int nHitSprite = floorHit & 0x3fff; + if ((sprite[nHitSprite].cstat & 0x30) == 0) + { + xvel[nSprite] += mulscale(4, pSprite->x - sprite[nHitSprite].x, 2); + yvel[nSprite] += mulscale(4, pSprite->y - sprite[nHitSprite].y, 2); + moveHit = gSpriteHit[nXSprite].hit; + } + } + if (nVel > 0) + { + int t = divscale16(nVelClipped, nVel); + xvel[nSprite] -= mulscale16(t, xvel[nSprite]); + yvel[nSprite] -= mulscale16(t, yvel[nSprite]); + } + } + + if (xvel[nSprite] || yvel[nSprite]) + pSprite->ang = getangle(xvel[nSprite], yvel[nSprite]); + + if (moveHit != 0 && pXDebris->Impact && pXDebris->locked != 1 && !pXDebris->isTriggered) { + if (!pXDebris->Interrutable && pXDebris->state != pXDebris->restState) return; + + if (pSprite->lotag >= kThingBase && pSprite->lotag < kThingMax) + // if thing was turned in debris, change it's stat back so it will do on impact what it supposed to do... + //actPostSprite(nSprite, 4); // !!!! not working here for some reason + changespritestat(nSprite, 4); + + if (pXDebris->state == 1) trTriggerSprite(pSprite->xvel, pXDebris, COMMAND_ID_0); + else trTriggerSprite(pSprite->xvel, pXDebris, COMMAND_ID_1); + } +} bool ceilIsTooLow(spritetype* pSprite) { if (pSprite != NULL) { diff --git a/source/blood/src/actor.h b/source/blood/src/actor.h index bf25fa7cb..1c10ee06b 100644 --- a/source/blood/src/actor.h +++ b/source/blood/src/actor.h @@ -80,7 +80,7 @@ struct THINGINFO unsigned char at15; // xrepeat unsigned char at16; // yrepeat int at17[7]; // damage - int allowThrow; // By NoOne: indicates if kGDXCustomDude can throw it + bool allowThrow; // By NoOne: indicates if kCustomDude can throw it }; struct AMMOITEMDATA @@ -129,7 +129,7 @@ struct MissileType unsigned char atb; // yrepeat char atc; // shade unsigned char atd; // clipdist - int fireSound[2]; // By NoOne: predefined fire sounds. used by kGDXCustomDude, but can be used for something else. + int fireSound[2]; // By NoOne: predefined fire sounds. used by kCustomDude, but can be used for something else. }; struct EXPLOSION @@ -137,8 +137,8 @@ struct EXPLOSION unsigned char at0; char at1; // dmg char at2; // dmg rnd - int at3; // radius - int at7; + int radius; // radius + int dmgType; int atb; int atf; int at13; @@ -162,7 +162,19 @@ struct VECTORDATA { int at15; // blood splats int at19; // blood splat chance VECTORDATA_at1d at1d[15]; - int fireSound[2]; // By NoOne: predefined fire sounds. used by kGDXCustomDude, but can be used for something else. + int fireSound[2]; // By NoOne: predefined fire sounds. used by kCustomDude, but can be used for something else. +}; + +// by NoOne: sprite mass info for getSpriteMassBySize(); +struct SPRITEMASS { + int seqId; + short picnum; // mainly needs for moving debris + short xrepeat; + short yrepeat; + short clipdist; // mass multiplier + int mass; + short airVel; // mainly needs for moving debris + int fraction; // mainly needs for moving debris }; extern AMMOITEMDATA gAmmoItemData[]; @@ -208,7 +220,7 @@ int actSpriteIdToOwnerId(int nSprite); int actOwnerIdToSpriteId(int nSprite); bool actTypeInSector(int nSector, int nType); void actAllocateSpares(void); -void actInit(void); +void actInit(bool bSaveLoad); void ConcussSprite(int a1, spritetype *pSprite, int x, int y, int z, int a6); int actWallBounceVector(int *x, int *y, int nWall, int a4); int actFloorBounceVector(int *x, int *y, int *z, int nSector, int a5); @@ -258,5 +270,18 @@ int GetRandDataVal(int *rData, spritetype* pSprite); bool sfxPlayMissileSound(spritetype* pSprite, int missileId); bool sfxPlayVectorSound(spritetype* pSprite, int vectorId); spritetype* actSpawnCustomDude(spritetype* pSprite, int nDist); -int getDudeMassBySpriteSize(spritetype* pSprite); -bool ceilIsTooLow(spritetype* pSprite); \ No newline at end of file +int getSpriteMassBySize(spritetype* pSprite); +bool ceilIsTooLow(spritetype* pSprite); +void actBuildMissile(spritetype* pMissile, int nXSprite, int nSprite); +int isDebris(int nSprite); +int debrisGetFreeIndex(void); +void debrisMove(int listIndex); +void debrisConcuss(int nOwner, int listIndex, int x, int y, int z, int dmg); + +extern SPRITEMASS gSpriteMass[kMaxXSprites]; +extern short gProxySpritesList[kMaxSuperXSprites]; +extern short gSightSpritesList[kMaxSuperXSprites]; +extern short gPhysSpritesList[kMaxSuperXSprites]; +extern short gProxySpritesCount; +extern short gSightSpritesCount; +extern short gPhysSpritesCount; \ No newline at end of file diff --git a/source/blood/src/ai.cpp b/source/blood/src/ai.cpp index 810ce4bf2..bea67805f 100644 --- a/source/blood/src/ai.cpp +++ b/source/blood/src/ai.cpp @@ -111,8 +111,8 @@ void aiNewState(spritetype *pSprite, XSPRITE *pXSprite, AISTATE *pAIState) if (pAIState->at0 >= 0) { // By NoOne: Custom dude uses data2 to keep it's seqStartId switch (pSprite->type) { - case kGDXDudeUniversalCultist: - case kGDXGenDudeBurning: + case kCustomDude: + case kCustomDudeBurning: seqStartId = pXSprite->data2; break; } @@ -231,9 +231,9 @@ bool CanMove(spritetype *pSprite, int a2, int nAngle, int nRange) if (floorZ - bottom > 0x2000) return false; break; - case kGDXDudeUniversalCultist: - case kGDXGenDudeBurning: - if ((Crusher && !dudeIsImmune(pSprite, pXSector->damageType)) || xsprite[pSprite->extra].dudeGuard) return false; + case kCustomDude: + case kCustomDudeBurning: + if ((Crusher && !dudeIsImmune(pSprite, pXSector->damageType)) || ((Water || Underwater) && !canSwim(pSprite))) return false; return true; fallthrough__; case 203: @@ -421,7 +421,7 @@ void aiActivateDude(spritetype *pSprite, XSPRITE *pXSprite) break; } - case kGDXDudeUniversalCultist: + case kCustomDude: { DUDEEXTRA_at6_u1* pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1; pDudeExtraE->at8 = 1; @@ -432,12 +432,12 @@ void aiActivateDude(spritetype *pSprite, XSPRITE *pXSprite) else { aiNewState(pSprite, pXSprite, &GDXGenDudeSearchL); if (Chance(0x4000)) - sfxPlayGDXGenDudeSound(pSprite, 0, pXSprite->data3); + sfxPlayGDXGenDudeSound(pSprite, 0); } } else { if (Chance(0x4000)) - sfxPlayGDXGenDudeSound(pSprite, 0, pXSprite->data3); + sfxPlayGDXGenDudeSound(pSprite, 0); if (spriteIsUnderwater(pSprite, false)) aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); @@ -447,7 +447,7 @@ void aiActivateDude(spritetype *pSprite, XSPRITE *pXSprite) } break; } - case kGDXGenDudeBurning: + case kCustomDudeBurning: if (pXSprite->target == -1) aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch); else @@ -1048,24 +1048,24 @@ int aiDamageSprite(spritetype *pSprite, XSPRITE *pXSprite, int nSource, DAMAGE_T evKill(nSprite, 3, CALLBACK_ID_0); } break; - case kGDXGenDudeBurning: + case kCustomDudeBurning: if (Chance(0x2000) && gDudeExtra[pSprite->extra].at0 < (int)gFrameClock) { - sfxPlayGDXGenDudeSound(pSprite, 3, pXSprite->data3); + sfxPlayGDXGenDudeSound(pSprite, 3); gDudeExtra[pSprite->extra].at0 = (int)gFrameClock + 360; } if (pXSprite->burnTime == 0) pXSprite->burnTime = 2400; if (spriteIsUnderwater(pSprite, false)) { - pSprite->type = kGDXDudeUniversalCultist; + pSprite->type = kCustomDude; pXSprite->burnTime = 0; pXSprite->health = 1; // so it can be killed with flame weapons while underwater and if already was burning dude before. aiNewState(pSprite, pXSprite, &GDXGenDudeGotoW); } break; - case kGDXDudeUniversalCultist: + case kCustomDude: { if (nDmgType == DAMAGE_TYPE_1) { if (pXSprite->health <= pDudeInfo->fleeHealth) { - if (getNextIncarnation(pXSprite) == NULL) { + if (pXSprite->txID <= 0 || getNextIncarnation(pXSprite) == NULL) { removeDudeStuff(pSprite); if (pXSprite->data1 >= 459 && pXSprite->data1 < (459 + kExplodeMax) - 1) @@ -1083,10 +1083,10 @@ int aiDamageSprite(spritetype *pSprite, XSPRITE *pXSprite, int nSource, DAMAGE_T && gSysRes.Lookup(pXSprite->data2 + 3, "SEQ")) { aiPlay3DSound(pSprite, 361, AI_SFX_PRIORITY_0, -1); - sfxPlayGDXGenDudeSound(pSprite, 3, pXSprite->data3); - pSprite->type = kGDXGenDudeBurning; + sfxPlayGDXGenDudeSound(pSprite, 3); + pSprite->type = kCustomDudeBurning; - if (pXSprite->data2 == 11520) // don't inherit palette for burning if using default animation + if (pXSprite->data2 == kDefaultAnimationBase) // don't inherit palette for burning if using default animation pSprite->pal = 0; aiNewState(pSprite, pXSprite, &GDXGenDudeBurnGoto); @@ -1097,18 +1097,20 @@ int aiDamageSprite(spritetype *pSprite, XSPRITE *pXSprite, int nSource, DAMAGE_T } } else { - actKillDude(nSource, pSprite, nDmgType, nDamage); + actKillDude(nSource, pSprite, DAMAGE_TYPE_0, 65535); } } - } else if (pXSprite->aiState != &GDXGenDudeDodgeDmgD && pXSprite->aiState != &GDXGenDudeDodgeDmgL - && pXSprite->aiState != &GDXGenDudeDodgeDmgW) { + } else if (!inDodge(pXSprite->aiState)) { - if (Chance(getDodgeChance(pSprite))) { + if (Chance(getDodgeChance(pSprite)) || inIdle(pXSprite->aiState)) { if (!spriteIsUnderwater(pSprite, false)) { - if (!sub_5BDA8(pSprite, 14)) aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeDmgL); + if (!canDuck(pSprite) || !sub_5BDA8(pSprite, 14)) aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeDmgL); else aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeDmgD); + + if (Chance(0x0200)) + sfxPlayGDXGenDudeSound(pSprite, 1); } - else if (sub_5BDA8(pSprite, 13) && spriteIsUnderwater(pSprite, false)) + else if (sub_5BDA8(pSprite, 13)) aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeDmgW); } } @@ -1150,33 +1152,34 @@ void RecoilDude(spritetype *pSprite, XSPRITE *pXSprite) DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase]; switch (pSprite->type) { - case kGDXDudeUniversalCultist: + case kCustomDude: { - int mass = getDudeMassBySpriteSize(pSprite); int chance3 = getRecoilChance(pSprite); - if ((mass < 155 && !spriteIsUnderwater(pSprite, false) && pDudeExtra->at4) || (mass > 155 && Chance(chance3))) + int mass = getSpriteMassBySize(pSprite); int chance4 = getRecoilChance(pSprite); bool chance3 = Chance(chance4); + if (pDudeExtra->at4 && (inIdle(pXSprite->aiState) || mass < 155 || (mass >= 155 && chance3)) && !spriteIsUnderwater(pSprite, false)) { - sfxPlayGDXGenDudeSound(pSprite, 1, pXSprite->data3); + sfxPlayGDXGenDudeSound(pSprite, 1); - if (gSysRes.Lookup(pXSprite->data2 + 4, "SEQ")) aiNewState(pSprite, pXSprite, &GDXGenDudeRTesla); - else if (!v4 || (v4 && gGameOptions.nDifficulty == 0)) aiNewState(pSprite, pXSprite, &GDXGenDudeRecoilD); - else if (spriteIsUnderwater(pSprite, false)) aiNewState(pSprite, pXSprite, &GDXGenDudeRecoilW); + if (gSysRes.Lookup(pXSprite->data2 + 4, "SEQ")) { + GDXGenDudeRTesla.at18 = (Chance(chance4 * 2) ? &GDXGenDudeDodgeL : &GDXGenDudeDodgeDmgL); + aiNewState(pSprite, pXSprite, &GDXGenDudeRTesla); + } + else if (canDuck(pSprite) && (Chance(chance4) || gGameOptions.nDifficulty == 0)) aiNewState(pSprite, pXSprite, &GDXGenDudeRecoilD); + else if (canSwim(pSprite) && spriteIsUnderwater(pSprite, false)) aiNewState(pSprite, pXSprite, &GDXGenDudeRecoilW); else aiNewState(pSprite, pXSprite, &GDXGenDudeRecoilL); - - return; + break; } - if (pXSprite->aiState == &GDXGenDudeDodgeDmgW || pXSprite->aiState == &GDXGenDudeDodgeDmgD - || pXSprite->aiState == &GDXGenDudeDodgeDmgL) { - if (Chance(chance3)) sfxPlayGDXGenDudeSound(pSprite, 1, pXSprite->data3); - return; + if (inDodge(pXSprite->aiState)) { + sfxPlayGDXGenDudeSound(pSprite, 1); + break; } - if ((!dudeIsMelee(pXSprite) && mass < 155) || Chance(chance3)) { + if (inIdle(pXSprite->aiState) || chance3 || Chance(getRecoilChance(pSprite)) || (!dudeIsMelee(pXSprite) && mass < 155)) { - sfxPlayGDXGenDudeSound(pSprite, 1, pXSprite->data3); + sfxPlayGDXGenDudeSound(pSprite, 1); - if (!v4 || (v4 && gGameOptions.nDifficulty == 0)) aiNewState(pSprite, pXSprite, &GDXGenDudeRecoilD); - else if (spriteIsUnderwater(pSprite, false)) aiNewState(pSprite, pXSprite, &GDXGenDudeRecoilW); + if (canDuck(pSprite) && (Chance(chance4) || gGameOptions.nDifficulty == 0)) aiNewState(pSprite, pXSprite, &GDXGenDudeRecoilD); + else if (canSwim(pSprite) && spriteIsUnderwater(pSprite, false)) aiNewState(pSprite, pXSprite, &GDXGenDudeRecoilW); else aiNewState(pSprite, pXSprite, &GDXGenDudeRecoilL); } @@ -1221,7 +1224,7 @@ void RecoilDude(spritetype *pSprite, XSPRITE *pXSprite) case 240: aiNewState(pSprite, pXSprite, &cultistBurnGoto); break; - case kGDXGenDudeBurning: + case kCustomDudeBurning: aiNewState(pSprite, pXSprite, &GDXGenDudeBurnGoto); break; case 204: @@ -1234,9 +1237,9 @@ void RecoilDude(spritetype *pSprite, XSPRITE *pXSprite) case 203: case 205: aiPlay3DSound(pSprite, 1106, AI_SFX_PRIORITY_2, -1); - if (pDudeExtra->at4 && pXSprite->cumulDamage > pDudeInfo->startHealth/3) + if (pDudeExtra->at4 && pXSprite->data3 > pDudeInfo->startHealth/3) aiNewState(pSprite, pXSprite, &zombieATeslaRecoil); - else if (pXSprite->cumulDamage > pDudeInfo->startHealth/3) + else if (pXSprite->data3 > pDudeInfo->startHealth/3) aiNewState(pSprite, pXSprite, &zombieARecoil2); else aiNewState(pSprite, pXSprite, &zombieARecoil); @@ -1256,7 +1259,7 @@ void RecoilDude(spritetype *pSprite, XSPRITE *pXSprite) break; case 227: aiPlay3DSound(pSprite, 2302+Random(2), AI_SFX_PRIORITY_2, -1); - if (pDudeExtra->at4 && pXSprite->cumulDamage > pDudeInfo->startHealth/3) + if (pDudeExtra->at4 && pXSprite->data3 > pDudeInfo->startHealth/3) aiNewState(pSprite, pXSprite, &cerberusTeslaRecoil); else aiNewState(pSprite, pXSprite, &cerberusRecoil); @@ -1511,7 +1514,7 @@ void aiProcessDudes(void) } if (pXSprite->health > 0 && ((pDudeInfo->hinderDamage<<4) <= cumulDamage[nXSprite])) { - pXSprite->cumulDamage = cumulDamage[nXSprite]; + pXSprite->data3 = cumulDamage[nXSprite]; RecoilDude(pSprite, pXSprite); } } @@ -1540,7 +1543,7 @@ void aiInitSprite(spritetype *pSprite) pDudeExtra->at0 = 0; switch (pSprite->type) { - case kGDXDudeUniversalCultist: + case kCustomDude: { DUDEEXTRA_at6_u1* pDudeExtraE = &gDudeExtra[nXSprite].at6.u1; pDudeExtraE->at8 = 0; @@ -1549,7 +1552,7 @@ void aiInitSprite(spritetype *pSprite) aiNewState(pSprite, pXSprite, &GDXGenDudeIdleL); break; } - case kGDXGenDudeBurning: + case kCustomDudeBurning: aiNewState(pSprite, pXSprite, &GDXGenDudeBurnGoto); pXSprite->burnTime = 1200; break; @@ -1756,15 +1759,16 @@ void aiInitSprite(spritetype *pSprite) case 244: pSprite->hitag = 7; break; + case 225: // by NoOne: FakeDude type + break; // By NoOne: Allow put pods and tentacles on ceilings if sprite is y-flipped. case 221: case 222: case 223: case 224: - case 225: case 226: if ((pSprite->cstat & CSTAT_SPRITE_YFLIP) != 0) { - if (!(pSprite->hitag & kHitagExtBit)) // don't add autoaim for player if hitag 1 specified in editor. + if (!(pSprite->hitag & kModernTypeFlag1)) // don't add autoaim for player if hitag 1 specified in editor. pSprite->hitag = kHitagAutoAim; break; } diff --git a/source/blood/src/aiburn.cpp b/source/blood/src/aiburn.cpp index 307561bee..0b8477b30 100644 --- a/source/blood/src/aiburn.cpp +++ b/source/blood/src/aiburn.cpp @@ -123,7 +123,7 @@ static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite) case 252: aiNewState(pSprite, pXSprite, &tinycalebBurnSearch); break; - case kGDXGenDudeBurning: + case kCustomDudeBurning: aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch); break; } @@ -155,7 +155,7 @@ static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite) case 252: aiNewState(pSprite, pXSprite, &tinycalebBurnGoto); break; - case kGDXGenDudeBurning: + case kCustomDudeBurning: aiNewState(pSprite, pXSprite, &GDXGenDudeBurnGoto); break; } @@ -191,7 +191,7 @@ static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite) case 252: aiNewState(pSprite, pXSprite, &tinycalebBurnSearch); break; - case kGDXGenDudeBurning: + case kCustomDudeBurning: aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch); break; } @@ -229,7 +229,7 @@ static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite) case 252: aiNewState(pSprite, pXSprite, &tinycalebBurnAttack); break; - case kGDXGenDudeBurning: + case kCustomDudeBurning: aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch); break; } @@ -259,7 +259,7 @@ static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite) case 252: aiNewState(pSprite, pXSprite, &tinycalebBurnGoto); break; - case kGDXGenDudeBurning: + case kCustomDudeBurning: aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch); break; } diff --git a/source/blood/src/aiunicult.cpp b/source/blood/src/aiunicult.cpp index 7d514c347..95a463170 100644 --- a/source/blood/src/aiunicult.cpp +++ b/source/blood/src/aiunicult.cpp @@ -26,19 +26,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "pragmas.h" #include "mmulti.h" #include "common_game.h" - #include "actor.h" #include "ai.h" #include "aiunicult.h" #include "blood.h" #include "db.h" #include "dude.h" + #include "eventq.h" #include "globals.h" #include "levels.h" #include "player.h" #include "seq.h" #include "sfx.h" +#include "sound.h" #include "trig.h" #include "triggers.h" #include "endgame.h" @@ -52,15 +53,13 @@ static void thinkSearch(spritetype*, XSPRITE*); static void thinkGoto(spritetype*, XSPRITE*); static void thinkChase(spritetype*, XSPRITE*); static void forcePunch(spritetype*, XSPRITE*); +static void thinkTransform(spritetype*, XSPRITE*); static int nGDXGenDudeAttack1 = seqRegisterClient(GDXCultistAttack1); static int nGDXGenDudePunch = seqRegisterClient(punchCallback); static int nGDXGenDudeThrow1 = seqRegisterClient(ThrowCallback1); static int nGDXGenDudeThrow2 = seqRegisterClient(ThrowCallback2); -static bool gGDXGenDudePunch = false; - -//public static final int kSlopeThrow = -8192; AISTATE GDXGenDudeIdleL = { kAiStateIdle, 0, -1, 0, NULL, NULL, aiThinkTarget, NULL }; AISTATE GDXGenDudeIdleW = { kAiStateIdle, 13, -1, 0, NULL, NULL, aiThinkTarget, NULL }; AISTATE GDXGenDudeSearchL = { kAiStateSearch, 9, -1, 600, NULL, aiGenDudeMoveForward, thinkSearch, &GDXGenDudeIdleL }; @@ -71,9 +70,9 @@ AISTATE GDXGenDudeDodgeL = { kAiStateMove, 9, -1, 90, NULL, aiMoveDodge, NULL, & AISTATE GDXGenDudeDodgeD = { kAiStateMove, 14, -1, 90, NULL, aiMoveDodge, NULL, &GDXGenDudeChaseD }; AISTATE GDXGenDudeDodgeW = { kAiStateMove, 13, -1, 90, NULL, aiMoveDodge, NULL, &GDXGenDudeChaseW }; // Dodge when get damage -AISTATE GDXGenDudeDodgeDmgL = { kAiStateMove, 9, -1, 90, NULL, aiMoveDodge, NULL, &GDXGenDudeChaseL }; -AISTATE GDXGenDudeDodgeDmgD = { kAiStateMove, 14, -1, 90, NULL, aiMoveDodge, NULL, &GDXGenDudeChaseD }; -AISTATE GDXGenDudeDodgeDmgW = { kAiStateMove, 13, -1, 90, NULL, aiMoveDodge, NULL, &GDXGenDudeChaseW }; +AISTATE GDXGenDudeDodgeDmgL = { kAiStateMove, 9, -1, 60, NULL, aiMoveDodge, NULL, &GDXGenDudeChaseL }; +AISTATE GDXGenDudeDodgeDmgD = { kAiStateMove, 14, -1, 60, NULL, aiMoveDodge, NULL, &GDXGenDudeChaseD }; +AISTATE GDXGenDudeDodgeDmgW = { kAiStateMove, 13, -1, 60, NULL, aiMoveDodge, NULL, &GDXGenDudeChaseW }; // --------------------- AISTATE GDXGenDudeChaseL = { kAiStateChase, 9, -1, 0, NULL, aiGenDudeMoveForward, thinkChase, NULL }; AISTATE GDXGenDudeChaseD = { kAiStateChase, 14, -1, 0, NULL, aiGenDudeMoveForward, thinkChase, NULL }; @@ -81,56 +80,68 @@ AISTATE GDXGenDudeChaseW = { kAiStateChase, 13, -1, 0, NULL, aiGenDudeMoveForwar AISTATE GDXGenDudeFireL = { kAiStateChase, 6, nGDXGenDudeAttack1, 0, NULL, aiMoveTurn, thinkChase, &GDXGenDudeFireL }; AISTATE GDXGenDudeFireD = { kAiStateChase, 8, nGDXGenDudeAttack1, 0, NULL, aiMoveTurn, thinkChase, &GDXGenDudeFireD }; AISTATE GDXGenDudeFireW = { kAiStateChase, 8, nGDXGenDudeAttack1, 0, NULL, aiMoveTurn, thinkChase, &GDXGenDudeFireW }; -AISTATE GDXGenDudeFire2L = { kAiStateChase, 6, nGDXGenDudeAttack1, 0, NULL, NULL, thinkChase, &GDXGenDudeFire2L }; -AISTATE GDXGenDudeFire2D = { kAiStateChase, 8, nGDXGenDudeAttack1, 0, NULL, aiMoveTurn, NULL, &GDXGenDudeFire2D }; -AISTATE GDXGenDudeFire2W = { kAiStateChase, 8, nGDXGenDudeAttack1, 0, NULL, aiMoveTurn, NULL, &GDXGenDudeFire2W }; AISTATE GDXGenDudeRecoilL = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &GDXGenDudeChaseL }; AISTATE GDXGenDudeRecoilD = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &GDXGenDudeChaseD }; AISTATE GDXGenDudeRecoilW = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &GDXGenDudeChaseW }; AISTATE GDXGenDudeThrow = { kAiStateChase, 7, nGDXGenDudeThrow1, 0, NULL, NULL, NULL, &GDXGenDudeChaseL }; AISTATE GDXGenDudeThrow2 = { kAiStateChase, 7, nGDXGenDudeThrow2, 0, NULL, NULL, NULL, &GDXGenDudeChaseL }; -AISTATE GDXGenDudeRTesla = { kAiStateRecoil, 4, -1, 0, NULL, NULL, NULL, &GDXGenDudeDodgeL }; -AISTATE GDXGenDudeProne = { kAiStateIdle, 13, -1, 0, NULL, NULL, aiThinkTarget, NULL }; +AISTATE GDXGenDudeRTesla = { kAiStateRecoil, 4, -1, 0, NULL, NULL, NULL, &GDXGenDudeDodgeDmgL }; AISTATE GDXGenDudePunch = { kAiStateChase,10, nGDXGenDudePunch, 0, NULL, NULL, forcePunch, &GDXGenDudeChaseL }; -AISTATE GDXGenDudeTurn = { kAiStateChase, 0, -1, 0, NULL, aiMoveTurn, thinkChase, NULL }; +GENDUDESND gCustomDudeSnd[] = { + { 1003, 2, 0, true }, // spot sound + { 1013, 2, 2, true }, // pain sound + { 1018, 2, 4, false }, // death sound + { 1031, 2, 6, true }, // burning state sound + { 1018, 2, 8, false }, // explosive death or end of burning state sound + { 4021, 2, 10, true }, // target of dude is dead + { 1005, 2, 12, true }, // chase sound + { -1, 0, 14, false }, // weapon attack + { -1, 0, 15, false }, // throw attack + { -1, 0, 16, false }, // melee attack + { 9008, 0, 17, false }, // transforming in other dude +}; static void forcePunch(spritetype* pSprite, XSPRITE* pXSprite) { - // Required for those who don't have fire trigger in punch seq and for default animation - if (gGDXGenDudePunch == false && seqGetStatus(3, pSprite->extra) == -1) { - int nXSprite = pSprite->extra; - punchCallback(0,nXSprite); - } - gGDXGenDudePunch = false; + // Required for those who don't have fire trigger in punch seq and for default animation + if (pXSprite->data2 != kDefaultAnimationBase) { + Seq* pSeq = NULL; DICTNODE* hSeq = gSysRes.Lookup(pXSprite->data2 + 10, "SEQ"); + if ((pSeq = (Seq*)gSysRes.Load(hSeq)) != NULL) { + for (int i = 0; i < pSeq->nFrames; i++) + if (pSeq->frames[i].at5_5) return; + } + } + + if (seqGetStatus(3, pSprite->extra) == -1) + punchCallback(0,pSprite->extra); + } -static void punchCallback(int, int nXIndex){ - XSPRITE* pXSprite = &xsprite[nXIndex]; +static void punchCallback(int, int nXIndex) { + XSPRITE* pXSprite = &xsprite[nXIndex]; + if (pXSprite->target != -1) { int nSprite = pXSprite->reference; spritetype* pSprite = &sprite[nSprite]; - int nAngle = getangle(pXSprite->targetX - pSprite->x, pXSprite->targetY - pSprite->y); - int nZOffset1 = dudeInfo[pSprite->type - kDudeBase].eyeHeight/* * pSprite->yrepeat << 2*/; + int nZOffset1 = dudeInfo[pSprite->type - kDudeBase].eyeHeight * pSprite->yrepeat << 2; int nZOffset2 = 0; - if(pXSprite->target != -1) { - spritetype* pTarget = &sprite[pXSprite->target]; - if(IsDudeSprite(pTarget)) - nZOffset2 = dudeInfo[pTarget->type - kDudeBase].eyeHeight/* * pTarget->yrepeat << 2*/; + + spritetype* pTarget = &sprite[pXSprite->target]; + if(IsDudeSprite(pTarget)) + nZOffset2 = dudeInfo[pTarget->type - kDudeBase].eyeHeight * pTarget->yrepeat << 2; - int dx = Cos(nAngle) >> 16; - int dy = Sin(nAngle) >> 16; - int dz = nZOffset1 - nZOffset2; - - if (!sfxPlayGDXGenDudeSound(pSprite,9,pXSprite->data3)) - sfxPlay3DSound(pSprite, 530, 1, 0); - - actFireVector(pSprite, 0, 0, dx, dy, dz,VECTOR_TYPE_22); - } + int dx = Cos(pSprite->ang) >> 16; + int dy = Sin(pSprite->ang) >> 16; + int dz = nZOffset1 - nZOffset2; - gGDXGenDudePunch = true; + if (!sfxPlayGDXGenDudeSound(pSprite, 9)) + sfxPlay3DSound(pSprite, 530, 1, 0); + + actFireVector(pSprite, 0, 0, dx, dy, dz,VECTOR_TYPE_22); } +} static void GDXCultistAttack1(int, int nXIndex) { XSPRITE* pXSprite = &xsprite[nXIndex]; @@ -138,7 +149,7 @@ static void GDXCultistAttack1(int, int nXIndex) { spritetype* pSprite = &sprite[nSprite]; int dx, dy, dz; int weapon = pXSprite->data1; if (weapon >= 0 && weapon < kVectorMax) { - + int vector = pXSprite->data1; dx = Cos(pSprite->ang) >> 16; dy = Sin(pSprite->ang) >> 16; @@ -155,7 +166,7 @@ static void GDXCultistAttack1(int, int nXIndex) { } actFireVector(pSprite, 0, 0, dx, dy, dz,(VECTOR_TYPE)vector); - if (!sfxPlayGDXGenDudeSound(pSprite,7,pXSprite->data3)) + if (!sfxPlayGDXGenDudeSound(pSprite,7)) sfxPlayVectorSound(pSprite,vector); } else if (weapon >= kDudeBase && weapon < kDudeMax) { @@ -167,8 +178,6 @@ static void GDXCultistAttack1(int, int nXIndex) { gDudeExtra[pSprite->extra].at6.u1.at4++; pSpawned->owner = nSprite; pSpawned->x += dist + (Random3(dist)); - //pSpawned->z = pSprite->z; - //pSpawned->y = pSprite->y; if (pSpawned->extra > -1) { xsprite[pSpawned->extra].target = pXSprite->target; if (pXSprite->target > -1) @@ -176,37 +185,10 @@ static void GDXCultistAttack1(int, int nXIndex) { } gKillMgr.sub_263E0(1); - if (!sfxPlayGDXGenDudeSound(pSprite, 7, pXSprite->data3)) + if (!sfxPlayGDXGenDudeSound(pSprite, 7)) sfxPlay3DSoundCP(pSprite, 379, 1, 0, 0x10000 - Random3(0x3000)); - - /*spritetype* pEffect = gFX.fxSpawn((FX_ID)52, pSpawned->sectnum, pSpawned->x, pSpawned->y, pSpawned->z, pSpawned->ang); - if (pEffect != NULL) { - - pEffect->cstat = kSprOriginAlign | kSprFace; - pEffect->shade = -127; - switch (Random(3)) { - case 0: - pEffect->pal = 0; - break; - case 1: - pEffect->pal = 5; - break; - case 2: - pEffect->pal = 9; - break; - case 3: - pEffect->shade = 127; - pEffect->pal = 1; - default: - pEffect->pal = 6; - break; - } - int repeat = 64 + Random(50); - pEffect->xrepeat = repeat; - pEffect->yrepeat = repeat; - }*/ - - if (Chance(0x3500)) { + + if (Chance(0x5500)) { int state = checkAttackState(pSprite, pXSprite); switch (state) { case 1: @@ -220,12 +202,12 @@ static void GDXCultistAttack1(int, int nXIndex) { break; } } + } else if (weapon >= kMissileBase && weapon < kMissileMax) { dx = Cos(pSprite->ang) >> 16; dy = Sin(pSprite->ang) >> 16; dz = gDudeSlope[nXIndex]; - //dz = 0; // dispersal modifiers here dx += Random3(3000 - 1000 * gGameOptions.nDifficulty); @@ -233,7 +215,7 @@ static void GDXCultistAttack1(int, int nXIndex) { dz += Random3(1000 - 500 * gGameOptions.nDifficulty); actFireMissile(pSprite, 0, 0, dx, dy, dz, weapon); - if (!sfxPlayGDXGenDudeSound(pSprite,7,pXSprite->data3)) + if (!sfxPlayGDXGenDudeSound(pSprite,7)) sfxPlayMissileSound(pSprite, weapon); } } @@ -263,9 +245,9 @@ static void ThrowThing(int nXIndex, bool impact) { if (thingType >= kThingBase && thingType < kThingMax) { THINGINFO* pThinkInfo = &thingInfo[thingType - kThingBase]; - if (pThinkInfo->allowThrow == 1) { + if (pThinkInfo->allowThrow) { - if (!sfxPlayGDXGenDudeSound(pSprite, 8, pXSprite->data3)) + if (!sfxPlayGDXGenDudeSound(pSprite, 8)) sfxPlay3DSound(pSprite, 455, -1, 0); int dx = pTarget->x - pSprite->x; @@ -309,8 +291,8 @@ static void ThrowThing(int nXIndex, bool impact) { pThing->yrepeat = 24 + Random(42); pThing->cstat |= 0x0001; - if (Chance(0x3000)) pThing->cstat |= 0x0004; - if (Chance(0x3000)) pThing->cstat |= 0x0008; + if (Chance(0x5000)) pThing->cstat |= 0x0004; + if (Chance(0x5000)) pThing->cstat |= 0x0008; if (pThing->xrepeat > 60) xsprite[pThing->extra].data1 = 43; else if (pThing->xrepeat > 40) xsprite[pThing->extra].data1 = 33; @@ -379,7 +361,7 @@ static void thinkGoto( spritetype* pSprite, XSPRITE* pXSprite ) aiChooseDirection(pSprite, pXSprite, nAngle); // if reached target, change to search mode - if ( /*dist < M2X(10.0)*/ dist < 5120 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery ) { + if (dist < 5120 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery ) { if(spriteIsUnderwater(pSprite,false)) aiNewState(pSprite, pXSprite, &GDXGenDudeSearchW); else @@ -391,34 +373,17 @@ static void thinkGoto( spritetype* pSprite, XSPRITE* pXSprite ) static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) { - - if (Chance(0x3000)) GDXGenDudeRecoilL.at18 = &GDXGenDudeDodgeD; - else GDXGenDudeRecoilL.at18 = &GDXGenDudeChaseL; - - if (Chance(0x3000)) GDXGenDudeRecoilW.at18 = &GDXGenDudeDodgeW; - else GDXGenDudeRecoilW.at18 = &GDXGenDudeChaseW; - - if (Chance(0x3000)) GDXGenDudeRecoilD.at18 = &GDXGenDudeDodgeL; - else GDXGenDudeRecoilD.at18 = &GDXGenDudeChaseL; - if (pXSprite->target == -1) { - if(spriteIsUnderwater(pSprite,false)) - aiNewState(pSprite, pXSprite, &GDXGenDudeGotoW); - else - aiNewState(pSprite, pXSprite, &GDXGenDudeGotoL); + if(spriteIsUnderwater(pSprite,false)) aiNewState(pSprite, pXSprite, &GDXGenDudeGotoW); + else aiNewState(pSprite, pXSprite, &GDXGenDudeGotoL); return; - } - - int dx, dy, dist; - - - dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax); - DUDEINFO* pDudeInfo = &dudeInfo[pSprite->type - kDudeBase]; - dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites); + } dassert(pXSprite->target < kMaxSprites); + + + int dx, dy, dist; DUDEINFO* pDudeInfo = &dudeInfo[pSprite->type - kDudeBase]; + spritetype* pTarget = &sprite[pXSprite->target]; - XSPRITE* pXTarget = pTarget->extra > 0 ? &xsprite[pTarget->extra] : NULL; - if(!IsDudeSprite(pTarget)) - pXTarget = NULL; + XSPRITE* pXTarget = (!IsDudeSprite(pTarget) || pTarget->extra < 0) ? NULL : &xsprite[pTarget->extra]; // check target dx = pTarget->x - pSprite->x; @@ -429,46 +394,40 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) if ( pXTarget == NULL || pXTarget->health <= 0 ) { // target is dead - if(spriteIsUnderwater(pSprite,false)) + if(spriteIsUnderwater(pSprite,false)) aiNewState(pSprite, pXSprite, &GDXGenDudeSearchW); else { aiNewState(pSprite, pXSprite, &GDXGenDudeSearchL); - sfxPlayGDXGenDudeSound(pSprite,5,pXSprite->data3); + sfxPlayGDXGenDudeSound(pSprite,5); } - return; } - if ( IsPlayerSprite( pTarget ) ) + if (IsPlayerSprite(pTarget)) { PLAYER* pPlayer = &gPlayer[ pTarget->type - kDudePlayer1 ]; - if ( powerupCheck( pPlayer, 13 ) > 0 ) - { - if(spriteIsUnderwater(pSprite,false)) - aiNewState(pSprite, pXSprite, &GDXGenDudeSearchW); - else - aiNewState(pSprite, pXSprite, &GDXGenDudeSearchL); + if (powerupCheck( pPlayer, 13 ) > 0) { + if(spriteIsUnderwater(pSprite,false)) aiNewState(pSprite, pXSprite, &GDXGenDudeSearchW); + else aiNewState(pSprite, pXSprite, &GDXGenDudeSearchL); return; } } - dist = approxDist(dx, dy); - if ( dist <= pDudeInfo->seeDist ) { - int nAngle = getangle(dx, dy); - int losAngle = ((1024 + nAngle - pSprite->ang) & 2047) - 1024; - int eyeAboveZ = (pDudeInfo->eyeHeight * pSprite->yrepeat) << 2; - VECTORDATA* meleeVector = &gVectorData[22]; + dist = (int) approxDist(dx, dy); if (dist == 0) dist = 1; + int eyeAboveZ = pDudeInfo->eyeHeight * pSprite->yrepeat << 2; + if (dist > pDudeInfo->seeDist || !cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, + pSprite->x, pSprite->y, pSprite->z - eyeAboveZ, pSprite->sectnum)) { - // is there a line of sight to the target? - if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, - pSprite->x, pSprite->y, pSprite->z - eyeAboveZ, pSprite->sectnum)){ - // is the target visible? - - if (dist < pDudeInfo->seeDist && klabs(losAngle) <= pDudeInfo->periphery) { - aiSetTarget(pXSprite, pXSprite->target); - - if ((gFrameClock & 64) == 0 && Chance(0x1000) && !spriteIsUnderwater(pSprite,false)) - sfxPlayGDXGenDudeSound(pSprite,6,pXSprite->data3); + if (spriteIsUnderwater(pSprite, false)) aiNewState(pSprite, pXSprite, &GDXGenDudeGotoW); + else aiNewState(pSprite, pXSprite, &GDXGenDudeGotoL); + pXSprite->target = -1; + return; + } + + int nAngle = getangle(dx, dy); + int losAngle = ((kAng180 + nAngle - pSprite->ang) & 2047) - kAng180; + // is the target visible? + if (dist < pDudeInfo->seeDist && klabs(losAngle) <= pDudeInfo->periphery) { if (pXSprite->target < 0) aiSetTarget(pXSprite, pXSprite->target); if (((int)gFrameClock & 64) == 0 && Chance(0x3000) && !spriteIsUnderwater(pSprite, false)) @@ -477,357 +436,264 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) gDudeSlope[sprite[pXSprite->reference].extra] = (int)divscale(pTarget->z - pSprite->z, dist, 10); spritetype* pLeech = NULL; VECTORDATA* meleeVector = &gVectorData[22]; - if (pXSprite->data1 >= kThingBase && pXSprite->data1 < kThingMax) { - if (pXSprite->data1 == 431) pXSprite->data1 = kGDXThingCustomDudeLifeLeech; - if (klabs(losAngle) < kAng15) { - if (dist < 12264 && dist > 7680 && !spriteIsUnderwater(pSprite,false) && pXSprite->data1 != kGDXThingCustomDudeLifeLeech){ - int pHit = HitScan(pSprite, pSprite->z, dx, dy, 0, 16777280, 0); - switch(pHit){ - case 3: - aiNewState(pSprite, pXSprite, &GDXGenDudeThrow); - return; + if (pXSprite->data1 >= kThingBase && pXSprite->data1 < kThingMax) { + if (pXSprite->data1 == 431) pXSprite->data1 = kGDXThingCustomDudeLifeLeech; + if ((pLeech = leechIsDropped(pSprite)) != NULL && xsprite[pLeech->extra].target != pXSprite->target) + xsprite[pLeech->extra].target = pXSprite->target; - case 0: - case 4: - return; - case -1: - aiNewState(pSprite, pXSprite, &GDXGenDudeThrow); - return; - default: - aiNewState(pSprite, pXSprite, &GDXGenDudeThrow); - return; - } - - } else if (dist > 4072 && dist <= 9072 && !spriteIsUnderwater(pSprite,false) && pSprite->owner != kMaxSprites){ - if (pXSprite->data1 != kGDXThingCustomDudeLifeLeech && pXSprite->data1 != kGDXThingThrowableRock) { - aiNewState(pSprite, pXSprite, &GDXGenDudeThrow2); - } else { - - if (pXSprite->data1 == kGDXThingCustomDudeLifeLeech) { - if ((pLeech = leechIsDropped(pSprite)) == NULL){ - aiNewState(pSprite, pXSprite, &GDXGenDudeThrow2); - GDXGenDudeThrow2.at18 = &GDXGenDudeDodgeL; - return; - } - - XSPRITE* pXLeech = &xsprite[pLeech->extra]; - int ldist = getTargetDist(pTarget,pDudeInfo,pLeech); - if (ldist > 3 || !cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, - pLeech->x, pLeech->y, pLeech->z, pLeech->sectnum) || pXLeech->target == -1) { - - aiNewState(pSprite, pXSprite, &GDXGenDudeThrow2); - GDXGenDudeThrow2.at18 = &GDXGenDudeDodgeL; - - } else { - GDXGenDudeThrow2.at18 = &GDXGenDudeChaseL; - if (pXLeech->target != pXSprite->target) pXLeech->target = pXSprite->target; - if (dist > 5072 && Chance(0x3000)) { - if (Chance(0x2000)) - aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeL); - else - aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeD); - } else { - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); - } - } - - } else if (pXSprite->data1 == kGDXThingThrowableRock){ - if (Chance(0x2000)) - aiNewState(pSprite, pXSprite, &GDXGenDudeThrow2); - else - sfxPlayGDXGenDudeSound(pSprite,0,pXSprite->data3); - } - } - - return; - - } else if (dist <= meleeVector->maxDist) { - if (spriteIsUnderwater(pSprite,false)) { - if (Chance(0x7000)) - aiNewState(pSprite, pXSprite, &GDXGenDudePunch); - else - aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeW); - - } else { - if (Chance(0x7000)) - aiNewState(pSprite, pXSprite, &GDXGenDudePunch); - else - aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeL); - - } - return; - - } else { - int state = checkAttackState(pSprite, pXSprite); - - if(state == 1) - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); - - if(state == 2) { - if (Chance(0x3000)) - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseD); - else - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); - } - - if(state == 3) - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); - - return; - } - } - - } else { - - int defDist = 17920; int vdist = defDist; - if (pXSprite->data1 > 0 && pXSprite->data1 < kVectorMax) { - - switch (pXSprite->data1) { - case 19: - pXSprite->data1 = 2; - break; - } - - VECTORDATA* pVectorData = &gVectorData[pXSprite->data1]; - vdist = pVectorData->maxDist; - if (vdist <= 0 || vdist > defDist) - vdist = defDist; - - } else if (pXSprite->data1 >= kDudeBase && pXSprite->data1 < kDudeMax && pXSprite->data1 != kGDXDudeUniversalCultist) { - - if (gDudeExtra[pSprite->extra].at6.u1.at4 > 0) { - - updateTargetOfSlaves(pSprite); - - if (pXSprite->target >= 0 && sprite[pXSprite->target].owner == pSprite->xvel) { - aiSetTarget(pXSprite, pSprite->x, pSprite->y, pSprite->z); - return; - } - } - - if (gDudeExtra[pSprite->extra].at6.u1.at4 <= gGameOptions.nDifficulty && dist > meleeVector->maxDist) { - vdist = (vdist / 2) + Random(vdist / 2); - } - else if (dist <= meleeVector->maxDist) { - aiNewState(pSprite, pXSprite, &GDXGenDudePunch); - return; - } - else { - int state = checkAttackState(pSprite, pXSprite); - switch (state) { - case 1: - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); - return; - case 2: - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseD); - return; - default: - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); - return; - } - } - } else if (pXSprite->data1 >= kMissileBase && pXSprite->data1 < kMissileMax){ - // special handling for flame, explosive and life leech missiles - int mdist = 2500; - if (pXSprite->data1 != 303) mdist = 3000; - switch(pXSprite->data1){ - case 315: - // Pickup life leech if it was thrown previously - if ((pLeech = leechIsDropped(pSprite)) != NULL) - removeLeech(pLeech); - break; - case 303: - case 305: - case 312: - case 313: - case 314: - { - if (dist > mdist || pXSprite->locked == 1) break; - int state = checkAttackState(pSprite, pXSprite); - if (dist <= meleeVector->maxDist && Chance(0x7000)) { - aiNewState(pSprite, pXSprite, &GDXGenDudePunch); - return; - } else { - switch (state) { - case 1: - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); - return; - case 2: - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseD); - return; - default: - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); - return; - } - } - } - case 304: - case 308: - { - if (spriteIsUnderwater(pSprite, false)) { - if (dist <= meleeVector->maxDist) { - if (Chance(0x4000)) { - aiNewState(pSprite, pXSprite, &GDXGenDudePunch); - } - else { - aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeW); - } - } - else { - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); - } - return; - } - - vdist = 4200; if (((int)gFrameClock & 16) == 0) vdist += Random(800); - break; - } - } - } else if (pXSprite->data1 >= 459 && pXSprite->data1 < (459 + kExplodeMax) - 1) { - - int nType = pXSprite->data1 - 459; EXPLOSION* pExpl = &explodeInfo[nType]; - if (pExpl != NULL && - CheckProximity(pSprite, pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pExpl->at3 / 2) && - doExplosion(pSprite, nType)) { - - pXSprite->health = 1; - actDamageSprite(pSprite->xvel, pSprite, DAMAGE_TYPE_3, 65535); - - xvel[pSprite->xvel] = 0; - zvel[pSprite->xvel] = 0; - yvel[pSprite->xvel] = 0; - } + if (klabs(losAngle) < kAng15) { + if (dist < 12264 && dist > 7680 && !spriteIsUnderwater(pSprite, false) && pXSprite->data1 != kGDXThingCustomDudeLifeLeech) { + int pHit = HitScan(pSprite, pSprite->z, dx, dy, 0, 16777280, 0); + switch (pHit) { + case 0: + case 4: return; - - } else { - - // Scared dude - no weapon. Still can punch you sometimes. - int state = checkAttackState(pSprite, pXSprite); - if (Chance(0x0500) && !spriteIsUnderwater(pSprite,false)) - sfxPlayGDXGenDudeSound(pSprite,6,pXSprite->data3); - - if (Chance(0x5000)){ - switch (state){ - case 1: - aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeW); - break; - case 2: - aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeD); - break; - default: - aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeL); - break; - } - - pXSprite->target = -1; - - } else if (dist <= meleeVector->maxDist && Chance(0x7000)) { - aiNewState(pSprite, pXSprite, &GDXGenDudePunch); - } else { - switch (state){ - case 1: - aiNewState(pSprite, pXSprite, &GDXGenDudeSearchW); - break; - default: - aiNewState(pSprite, pXSprite, &GDXGenDudeSearchL); - break; - } - - pXSprite->target = -1; - } - + default: + aiNewState(pSprite, pXSprite, &GDXGenDudeThrow); return; } - int state = checkAttackState(pSprite, pXSprite); - if (dist > vdist && pXSprite->aiState == &GDXGenDudeChaseD) - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); - - if (dist < vdist && klabs(losAngle) < 35 /*&& klabs(losAngle) < kAngle5*/) { - if (vdist > 1512){ - switch(state){ - case 1: - aiNewState(pSprite, pXSprite, &GDXGenDudeFireW); - pXSprite->aiState->at18 = &GDXGenDudeFireW; - break; - case 2: - aiNewState(pSprite, pXSprite, &GDXGenDudeFireD); - pXSprite->aiState->at18 = &GDXGenDudeFireD; - break; - - default: - aiNewState(pSprite, pXSprite, &GDXGenDudeFireL); - pXSprite->aiState->at18 = &GDXGenDudeFireL; - break; - } - } else { - switch(state){ - case 1: - aiNewState(pSprite, pXSprite, &GDXGenDudeFire2W); - pXSprite->aiState->at18 = &GDXGenDudeFire2W; - break; - case 2: - aiNewState(pSprite, pXSprite, &GDXGenDudeFire2D); - pXSprite->aiState->at18 = &GDXGenDudeFire2D; - break; - - default: - aiNewState(pSprite, pXSprite, &GDXGenDudeFire2L); - pXSprite->aiState->at18 = &GDXGenDudeFire2L; - break; - } - } - } else { - int nSeq = 6; if (state < 3) nSeq = 8; - if (seqGetID(3, pSprite->extra) == pDudeInfo->seqStartID + nSeq) { - switch(state){ - case 1: - pXSprite->aiState->at18 = &GDXGenDudeChaseW; - break; - case 2: - pXSprite->aiState->at18 = &GDXGenDudeChaseD; - break; - default: - pXSprite->aiState->at18 = &GDXGenDudeChaseL; - break; - } - } else { - if(pXSprite->aiState == &GDXGenDudeChaseL || pXSprite->aiState == &GDXGenDudeChaseD || - pXSprite->aiState == &GDXGenDudeChaseW || pXSprite->aiState == &GDXGenDudeFireL || - pXSprite->aiState == &GDXGenDudeFireD || pXSprite->aiState == &GDXGenDudeFireW) - return; - - switch (state) { - case 1: - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); - pXSprite->aiState->at18 = &GDXGenDudeFireW; - break; - case 2: - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseD); - pXSprite->aiState->at18 = &GDXGenDudeFireD; - break; - default: - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); - pXSprite->aiState->at18 = &GDXGenDudeFireL; - break; - } - } - } - + } + else if (dist > 4072 && dist <= 9072 && !spriteIsUnderwater(pSprite, false) && pSprite->owner != (kMaxSprites - 1)) { + switch (pXSprite->data1) { + case kGDXThingCustomDudeLifeLeech: + { + if (pLeech == NULL) { + aiNewState(pSprite, pXSprite, &GDXGenDudeThrow2); + GDXGenDudeThrow2.at18 = &GDXGenDudeDodgeL; + return; + } + + XSPRITE* pXLeech = &xsprite[pLeech->extra]; + int ldist = getTargetDist(pTarget, pDudeInfo, pLeech); + //System.out.println("LDIST: "+ldist); + if (ldist > 3 || !cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, + pLeech->x, pLeech->y, pLeech->z, pLeech->sectnum) || pXLeech->target == -1) { + + aiNewState(pSprite, pXSprite, &GDXGenDudeThrow2); + GDXGenDudeThrow2.at18 = &GDXGenDudeDodgeL; + + } + else { + GDXGenDudeThrow2.at18 = &GDXGenDudeChaseL; + if (pXLeech->target != pXSprite->target) pXLeech->target = pXSprite->target; + if (dist > 5072 && Chance(0x5000)) { + if (!canDuck(pSprite) || Chance(0x4000)) aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeL); + else aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeD); + } + else { + aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); + } + } + } + return; + case kGDXThingThrowableRock: + if (Chance(0x4000)) aiNewState(pSprite, pXSprite, &GDXGenDudeThrow2); + else sfxPlayGDXGenDudeSound(pSprite, 0); + return; + default: + aiNewState(pSprite, pXSprite, &GDXGenDudeThrow2); + return; + } + + } + else if (dist <= meleeVector->maxDist) { + + if (spriteIsUnderwater(pSprite, false)) { + if (Chance(0x9000)) aiNewState(pSprite, pXSprite, &GDXGenDudePunch); + else aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeW); + + } + else if (Chance(0x9000)) aiNewState(pSprite, pXSprite, &GDXGenDudePunch); + else aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeL); + return; + + } + else { + int state = checkAttackState(pSprite, pXSprite); + if (state == 1) aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); + else if (state == 2) { + if (Chance(0x5000)) aiNewState(pSprite, pXSprite, &GDXGenDudeChaseD); + else aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); + } + else aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); + return; + } + } + + } + else { + + int defDist = 17920; int vdist = defDist; + + if (pXSprite->data1 > 0 && pXSprite->data1 < kVectorMax) { + + switch (pXSprite->data1) { + case 19: + pXSprite->data1 = 2; + break; + } + + VECTORDATA* pVectorData = &gVectorData[pXSprite->data1]; + vdist = pVectorData->maxDist; + if (vdist <= 0 || vdist > defDist) + vdist = defDist; + + } + else if (pXSprite->data1 >= kDudeBase && pXSprite->data1 < kDudeMax) { + + if (gDudeExtra[pSprite->extra].at6.u1.at4 > 0) { + updateTargetOfSlaves(pSprite); + if (pXSprite->target >= 0 && sprite[pXSprite->target].owner == pSprite->xvel) { + aiSetTarget(pXSprite, pSprite->x, pSprite->y, pSprite->z); + return; + } + } + + int state = checkAttackState(pSprite, pXSprite); + if (gDudeExtra[pSprite->extra].at6.u1.at4 <= gGameOptions.nDifficulty && dist > meleeVector->maxDist) { + vdist = (vdist / 2) + Random(vdist / 2); + } + else if (dist <= meleeVector->maxDist) { + aiNewState(pSprite, pXSprite, &GDXGenDudePunch); + return; + } + else { + + if (state == 1) aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); + else if (state == 2) aiNewState(pSprite, pXSprite, &GDXGenDudeChaseD); + else aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); + return; + } + + + + } + else if (pXSprite->data1 >= kMissileBase && pXSprite->data1 < kMissileMax) { + // special handling for flame, explosive and life leech missiles + int state = checkAttackState(pSprite, pXSprite); + int mdist = (pXSprite->data1 != 303) ? 3000 : 2500; + switch (pXSprite->data1) { + case 315: + // pickup life leech if it was thrown previously + if ((pLeech = leechIsDropped(pSprite)) != NULL) removeLeech(pLeech); + break; + case 303: + case 305: + case 312: + case 313: + case 314: + if (dist > mdist || pXSprite->locked == 1) break; + else if (dist <= meleeVector->maxDist && Chance(0x9000)) + aiNewState(pSprite, pXSprite, &GDXGenDudePunch); + else if (state == 1) aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); + else if (state == 2) aiNewState(pSprite, pXSprite, &GDXGenDudeChaseD); + else aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); + return; + + + case 304: + case 308: + if (spriteIsUnderwater(pSprite, false)) { + if (dist > meleeVector->maxDist) aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); + else if (Chance(0x8000)) aiNewState(pSprite, pXSprite, &GDXGenDudePunch); + else aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeW); + return; + } + + vdist = 4200; if (((int)gFrameClock & 16) == 0) vdist += Random(800); + break; + } + + } + else if (pXSprite->data1 >= 459 && pXSprite->data1 < (459 + kExplodeMax) - 1) { + + int nType = pXSprite->data1 - 459; EXPLOSION* pExpl = &explodeInfo[nType]; + if (pExpl != NULL && CheckProximity(pSprite, pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pExpl->radius / 2) + && doExplosion(pSprite, nType)) { + + pXSprite->health = 1; + actDamageSprite(pSprite->xvel, pSprite, DAMAGE_TYPE_3, 65535); + + xvel[pSprite->xvel] = 0; + zvel[pSprite->xvel] = 0; + yvel[pSprite->xvel] = 0; + } return; + + // scared dude - no weapon. Still can punch you sometimes. + } + else { + + int state = checkAttackState(pSprite, pXSprite); + if (Chance(0x0500) && !spriteIsUnderwater(pSprite, false)) + sfxPlayGDXGenDudeSound(pSprite, 6); + + if (Chance(0x0200)) { + if (dist <= meleeVector->maxDist) aiNewState(pSprite, pXSprite, &GDXGenDudePunch); + else if (state == 1) aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeW); + else if (state == 2) aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeD); + else aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeL); + } + else if (state == 1) aiNewState(pSprite, pXSprite, &GDXGenDudeSearchW); + else aiNewState(pSprite, pXSprite, &GDXGenDudeSearchL); + + aiSetTarget(pXSprite, pSprite->x, pSprite->y, pSprite->z); + return; + } + + + if (dist <= vdist && pXSprite->aiState == &GDXGenDudeChaseD) + aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); + + int state = checkAttackState(pSprite, pXSprite); + if (dist < vdist && /*klabs(losAngle) < 32*/ klabs(losAngle) < kAng5) { + + switch (state) { + case 1: + aiNewState(pSprite, pXSprite, &GDXGenDudeFireW); + pXSprite->aiState->at18 = &GDXGenDudeFireW; + return; + case 2: + aiNewState(pSprite, pXSprite, &GDXGenDudeFireD); + pXSprite->aiState->at18 = &GDXGenDudeFireD; + return; + default: + aiNewState(pSprite, pXSprite, &GDXGenDudeFireL); + pXSprite->aiState->at18 = &GDXGenDudeFireL; + return; + } + + } + else { + + if (seqGetID(3, pSprite->extra) == pXSprite->data2 + (state < 3) ? 8 : 6) { + if (state == 1) pXSprite->aiState->at18 = &GDXGenDudeChaseW; + else if (state == 2) pXSprite->aiState->at18 = &GDXGenDudeChaseD; + else pXSprite->aiState->at18 = &GDXGenDudeChaseL; + } + else if (state == 1 && pXSprite->aiState != &GDXGenDudeChaseW && pXSprite->aiState != &GDXGenDudeFireW) { + aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); + pXSprite->aiState->at18 = &GDXGenDudeFireW; + + } + else if (state == 2 && pXSprite->aiState != &GDXGenDudeChaseD && pXSprite->aiState != &GDXGenDudeFireD) { + aiNewState(pSprite, pXSprite, &GDXGenDudeChaseD); + pXSprite->aiState->at18 = &GDXGenDudeFireD; + + } + else if (pXSprite->aiState != &GDXGenDudeChaseL && pXSprite->aiState != &GDXGenDudeFireL) { + aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); + pXSprite->aiState->at18 = &GDXGenDudeFireL; + } + } } } - - if(spriteIsUnderwater(pSprite,false)) { - aiNewState(pSprite, pXSprite, &GDXGenDudeGotoW); - } else { - aiNewState(pSprite, pXSprite, &GDXGenDudeGotoL); - } - pXSprite->target = -1; } + int checkAttackState(spritetype* pSprite, XSPRITE* pXSprite) { UNREFERENCED_PARAMETER(pXSprite); if (sub_5BDA8(pSprite, 14) || spriteIsUnderwater(pSprite,false)) @@ -940,125 +806,43 @@ void aiGenDudeMoveForward(spritetype* pSprite, XSPRITE* pXSprite ) { yvel[pSprite->xvel] += mulscale(sin, frontSpeed, 30); } -bool sfxPlayGDXGenDudeSound(spritetype* pSprite, int mode, int data) { - int sndId = -1; int rand = 0; bool gotSnd = true; - - switch (mode){ - // spot sound - case 0: - rand = 2; sndId = 1003; - if (data > 0) - sndId = data; - break; - // pain sound - case 1: - rand = 2; sndId = 1013; - if (data > 0) - sndId = data + 2; - break; - // death sound - case 2: - rand = 2; sndId = 1018; - if (data > 0) - sndId = data + 4; - break; - // burning state sound - case 3: - rand = 2; sndId = 1031; - if (data > 0) - sndId = data + 6; - break; - // explosive death or end of burning state sound - case 4: - rand = 2; sndId = 1018; - if (data > 0) - sndId = data + 8; - break; - // target of dude is dead - case 5: - rand = 2; sndId = 4021; - if (data > 0) - sndId = data + 10; - break; - // roam sounds - case 6: - rand = 2; sndId = 1005; - if (data > 0) - sndId = data + 12; - break; - // weapon attack - case 7: - if (data > 0) - sndId = data + 14; - break; - // throw attack - case 8: - if (data > 0) - sndId = data + 15; - break; - // melee attack - case 9: - if (data > 0) - sndId = data + 16; - break; - // transforming in other dude - case 10: - sndId = 9008; - if (data > 0) - sndId = data + 17; - break; - default: - return false; - - } - - +bool sfxPlayGDXGenDudeSound(spritetype* pSprite, int mode) { + + if (mode < 0 || mode >= kMaxGenDudeSndMode) return false; + GENDUDESND* sndInfo =& gCustomDudeSnd[mode]; bool gotSnd = false; + short sndStartId = xsprite[pSprite->extra].sysData1; int rand = sndInfo->randomRange; + int sndId = (sndStartId <= 0) ? sndInfo->defaultSndId : sndStartId + sndInfo->sndIdOffset; + if (sndId < 0) return false; - else if (data <= 0) sndId = sndId + Random(rand); + else if (sndStartId <= 0) { sndId += Random(rand); gotSnd = true; } else { - - int maxRetries = 5; gotSnd = false; + // Let's try to get random snd - while(maxRetries-- > 0){ + int maxRetries = 5; + while (maxRetries-- > 0) { int random = Random(rand); - if (gSysRes.Lookup(sndId + random, "SFX")){ - sndId = sndId + random; + if (!gSoundRes.Lookup(sndId + random, "SFX")) continue; + sndId = sndId + random; + gotSnd = true; + break; + } + + // If no success in getting random snd, get first existing one + if (gotSnd == false) { + int maxSndId = sndId + rand; + while (sndId++ <= maxSndId) { + if (!gSoundRes.Lookup(sndId, "SFX")) continue; gotSnd = true; break; } } - - // If no success in getting random snd, get first existing one - if (gotSnd == false){ - int max = sndId + rand; - while(sndId++ <= max){ - if (gSysRes.Lookup(sndId, "SFX")) { - gotSnd = true; - break; - } - } - } + } - if (gotSnd) { - switch (mode){ - // case 1: - case 2: - case 4: - case 7: - case 8: - case 9: - case 10: - sfxPlay3DSound(pSprite, sndId, -1, 0); - break; - default: - aiPlay3DSound(pSprite, sndId, AI_SFX_PRIORITY_2, -1); - break; - } - return true; - } - - return false; + if (gotSnd == false) return false; + else if (sndInfo->aiPlaySound) aiPlay3DSound(pSprite, sndId, AI_SFX_PRIORITY_2, -1); + else sfxPlay3DSound(pSprite, sndId, -1, 0); + return true; } @@ -1093,7 +877,8 @@ void removeDudeStuff(spritetype* pSprite) { case 401: case 402: case 433: - deletesprite(nSprite); + sprite[nSprite].lotag = 0; + actPostSprite(sprite[nSprite].xvel, kStatFree); break; case kGDXThingCustomDudeLifeLeech: killDudeLeech(&sprite[nSprite]); @@ -1111,33 +896,39 @@ void removeLeech(spritetype* pLeech, bool delSprite) { if (pLeech != NULL) { spritetype* pEffect = gFX.fxSpawn((FX_ID)52,pLeech->sectnum,pLeech->x,pLeech->y,pLeech->z,pLeech->ang); if (pEffect != NULL) { - pEffect->cstat = CSTAT_SPRITE_ALIGNMENT_FLOOR; + pEffect->cstat = CSTAT_SPRITE_ALIGNMENT_FACING; pEffect->pal = 6; int repeat = 64 + Random(50); pEffect->xrepeat = repeat; pEffect->yrepeat = repeat; } sfxPlay3DSoundCP(pLeech, 490, -1, 0,60000); - if (delSprite) + if (delSprite) { + pLeech->type = 0; actPostSprite(pLeech->index, kStatFree); + } } } void killDudeLeech(spritetype* pLeech) { if (pLeech != NULL) { - //removeLeech(pLeech, false); actDamageSprite(pLeech->owner, pLeech, DAMAGE_TYPE_3, 65535); sfxPlay3DSoundCP(pLeech, 522, -1, 0, 60000); } } XSPRITE* getNextIncarnation(XSPRITE* pXSprite) { - if (pXSprite->txID > 0) { - for (short nSprite = headspritestat[7]; nSprite >= 0; nSprite = nextspritestat[nSprite]) { - if (!IsDudeSprite(&sprite[nSprite]) || sprite[nSprite].extra < 0) continue; - if (xsprite[sprite[nSprite].extra].rxID == pXSprite->txID && xsprite[sprite[nSprite].extra].health > 0) - return &xsprite[sprite[nSprite].extra]; + for (int i = bucketHead[pXSprite->txID]; i < bucketHead[pXSprite->txID + 1]; i++) { + if (rxBucket[i].type != 3 || rxBucket[i].index == pXSprite->reference) + continue; + + switch (sprite[rxBucket[i].index].statnum) { + case 6: + case 7: // inactive (ambush) dudes + if (xsprite[sprite[rxBucket[i].index].extra].health > 0) + return &xsprite[sprite[rxBucket[i].index].extra]; } + } return NULL; } @@ -1152,33 +943,36 @@ bool dudeIsMelee(XSPRITE* pXSprite) { if (vdist > 0 && vdist <= meleeDist) return true; - } - else { + } else { if (pXSprite->data1 >= 459 && pXSprite->data1 < (459 + kExplodeMax) - 1) return true; - switch (pXSprite->data1) { - case 304: - case 308: - return true; - default: - return false; - } + /*switch (pXSprite->data1) { + case 304: + case 308: + return true; + default: + return false; + }*/ } return false; } +int getBaseChanceModifier(int baseChance) { + return ((gGameOptions.nDifficulty > 0) ? baseChance - (0x0300 * gGameOptions.nDifficulty) : baseChance); +} + int getRecoilChance(spritetype* pSprite) { - int mass = getDudeMassBySpriteSize(pSprite); - int cumulDmg = 0; int baseChance = 0x4000; + int mass = getSpriteMassBySize(pSprite); + int cumulDmg = 0; int baseChance = getBaseChanceModifier(0x8000); if (pSprite->extra >= 0) { XSPRITE pXSprite = xsprite[pSprite->extra]; baseChance += (pXSprite.burnTime / 2); - cumulDmg = pXSprite.cumulDamage; + cumulDmg = pXSprite.data3; if (dudeIsMelee(&pXSprite)) - baseChance = 0x500; + baseChance = 0x700; } baseChance += cumulDmg; @@ -1188,12 +982,12 @@ int getRecoilChance(spritetype* pSprite) { } int getDodgeChance(spritetype* pSprite) { - int mass = getDudeMassBySpriteSize(pSprite); int baseChance = 0x1000; + int mass = getSpriteMassBySize(pSprite); int baseChance = getBaseChanceModifier(0x4000); if (pSprite->extra >= 0) { XSPRITE pXSprite = xsprite[pSprite->extra]; baseChance += pXSprite.burnTime; if (dudeIsMelee(&pXSprite)) - baseChance = 0x200; + baseChance = 0x400; } int chance = ((baseChance / mass) << 7); @@ -1259,7 +1053,7 @@ bool doExplosion(spritetype* pSprite, int nType) { pExplosion->yrepeat = pExpl->at0; pExplosion->xrepeat = pExpl->at0; pExplosion->lotag = nType; - pExplosion->cstat |= CSTAT_SPRITE_INVISIBLE | CSTAT_SPRITE_YCENTER; + pExplosion->cstat |= CSTAT_SPRITE_INVISIBLE | CSTAT_SPRITE_ALIGNMENT_SLAB; pExplosion->owner = pSprite->xvel; if (pExplosion->extra >= 0) { @@ -1307,4 +1101,67 @@ void updateTargetOfSlaves(spritetype* pSprite) { return; } + +bool canSwim(spritetype* pSprite) { + return (gSysRes.Lookup(xsprite[pSprite->extra].data2 + 8, "SEQ") && gSysRes.Lookup(xsprite[pSprite->extra].data2 + 13, "SEQ") + && gSysRes.Lookup(xsprite[pSprite->extra].data2 + 17, "SEQ")); +} + + +bool canDuck(spritetype* pSprite) { + return (gSysRes.Lookup(xsprite[pSprite->extra].data2 + 8, "SEQ") && gSysRes.Lookup(xsprite[pSprite->extra].data2 + 14, "SEQ")); + +} + +bool CDCanMove(spritetype* pSprite) { + return (gSysRes.Lookup(xsprite[pSprite->extra].data2 + 9, "SEQ") && gSysRes.Lookup(xsprite[pSprite->extra].data2 + 13, "SEQ") + && gSysRes.Lookup(xsprite[pSprite->extra].data2 + 14, "SEQ")); + +} + +bool inDodge(AISTATE* aiState) { + return (aiState == &GDXGenDudeDodgeDmgW || aiState == &GDXGenDudeDodgeDmgL || aiState == &GDXGenDudeDodgeDmgD); +} + +bool inIdle(AISTATE* aiState) { + return (aiState == &GDXGenDudeIdleW || aiState == &GDXGenDudeIdleL); +} + +int getSeqStartId(XSPRITE* pXSprite) { + int seqStartId = dudeInfo[sprite[pXSprite->reference].type - kDudeBase].seqStartID; + // Store seqStartId in data2 field + if (pXSprite->data2 > 0) { + seqStartId = pXSprite->data2; + // check for full set of animations + for (int i = seqStartId; i <= seqStartId + 19; i++) { + + // exceptions + switch (i - seqStartId) { + case 3: // burning dude + case 4: // electrocution + case 8: // attack u/d + case 11: // reserved + case 12: // reserved + case 13: // move u + case 14: // move d + case 16: // burning death 2 + case 17: // idle w + case 18: // transformation in another dude + case 19: // reserved + continue; + } + + if (!gSysRes.Lookup(i, "SEQ")) { + pXSprite->data2 = dudeInfo[sprite[pXSprite->reference].type - kDudeBase].seqStartID; + return pXSprite->data2; + } + + } + + } else { + pXSprite->data2 = seqStartId; + } + + return seqStartId; +} ////////// diff --git a/source/blood/src/aiunicult.h b/source/blood/src/aiunicult.h index da9a64284..c89602e31 100644 --- a/source/blood/src/aiunicult.h +++ b/source/blood/src/aiunicult.h @@ -25,6 +25,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "ai.h" #include "eventq.h" +#define kMaxGenDudeSndMode 11 +#define kDefaultAnimationBase 11520 + + extern AISTATE GDXGenDudeIdleL; extern AISTATE GDXGenDudeIdleW; extern AISTATE GDXGenDudeSearchL; @@ -43,18 +47,24 @@ extern AISTATE GDXGenDudeChaseW; extern AISTATE GDXGenDudeFireL; extern AISTATE GDXGenDudeFireD; extern AISTATE GDXGenDudeFireW; -extern AISTATE GDXGenDudeFire2L; -extern AISTATE GDXGenDudeFire2D; -extern AISTATE GDXGenDudeFire2W; extern AISTATE GDXGenDudeRecoilL; extern AISTATE GDXGenDudeRecoilD; extern AISTATE GDXGenDudeRecoilW; -extern AISTATE GDGenDudeThrow; -extern AISTATE GDGenDudeThrow2; +extern AISTATE GDXGenDudeThrow; +extern AISTATE GDXGenDudeThrow2; extern AISTATE GDXGenDudePunch; extern AISTATE GDXGenDudeRTesla; -extern AISTATE GDXGenDudeProne; -extern AISTATE GDXGenDudeTurn; +extern AISTATE GDXGenDudeTransform; + +struct GENDUDESND +{ + int defaultSndId; + int randomRange; + int sndIdOffset; // relative to data3 + bool aiPlaySound; // false = sfxStart3DSound(); +}; + +extern GENDUDESND gCustomDudeSnd[]; XSPRITE* getNextIncarnation(XSPRITE* pXSprite); void killDudeLeech(spritetype* pLeech); @@ -62,7 +72,7 @@ void removeLeech(spritetype* pLeech, bool delSprite = true); void removeDudeStuff(spritetype* pSprite); spritetype* leechIsDropped(spritetype* pSprite); bool spriteIsUnderwater(spritetype* pSprite, bool oldWay); -bool sfxPlayGDXGenDudeSound(spritetype* pSprite, int mode, int data); +bool sfxPlayGDXGenDudeSound(spritetype* pSprite, int mode); void aiGenDudeMoveForward(spritetype* pSprite, XSPRITE* pXSprite); int getGenDudeMoveSpeed(spritetype* pSprite, int which, bool mul, bool shift); bool TargetNearThing(spritetype* pSprite, int thingType); @@ -72,4 +82,10 @@ void dudeLeechOperate(spritetype* pSprite, XSPRITE* pXSprite, EVENT a3); int getDodgeChance(spritetype* pSprite); int getRecoilChance(spritetype* pSprite); bool dudeIsMelee(XSPRITE* pXSprite); -void updateTargetOfSlaves(spritetype* pSprite); \ No newline at end of file +void updateTargetOfSlaves(spritetype* pSprite); +bool canSwim(spritetype* pSprite); +bool canDuck(spritetype* pSprite); +bool CDCanMove(spritetype* pSprite); +bool inDodge(AISTATE* aiState); +bool inIdle(AISTATE* aiState); +int getSeqStartId(XSPRITE* pXSprite); \ No newline at end of file diff --git a/source/blood/src/blood.cpp b/source/blood/src/blood.cpp index 8f2d33a67..024c8c54b 100644 --- a/source/blood/src/blood.cpp +++ b/source/blood/src/blood.cpp @@ -475,12 +475,12 @@ void PreloadCache(void) if (totalclock - clock >= 1) { - clock = totalclock.Ticks(); + clock = totalclock; percentDisplayed++; } } - clock = totalclock.Ticks(); + clock = totalclock; } } } @@ -522,6 +522,10 @@ void StartLevel(GAMEOPTIONS *gameOptions) gGameOptions.uGameFlags |= 4; if ((gGameOptions.uGameFlags&4) && gDemo.at1 == 0) levelPlayIntroScene(gGameOptions.nEpisode); + + /////// + gGameOptions.weaponsV10x = gWeaponsV10x; + /////// } else if (gGameOptions.nGameType > 0 && !(gGameOptions.uGameFlags&1)) { @@ -540,6 +544,10 @@ void StartLevel(GAMEOPTIONS *gameOptions) else levelSetupOptions(gGameOptions.nEpisode, gGameOptions.nLevel); + /////// + gGameOptions.weaponsV10x = gPacketStartGame.weaponsV10x; + /////// + gBlueFlagDropped = false; gRedFlagDropped = false; } @@ -552,7 +560,7 @@ void StartLevel(GAMEOPTIONS *gameOptions) } } bVanilla = gDemo.at1 && gDemo.m_bLegacy; - //blooddemohack = 1;//bVanilla; + blooddemohack = 2;//bVanilla; memset(xsprite,0,sizeof(xsprite)); memset(sprite,0,kMaxSprites*sizeof(spritetype)); drawLoadingScreen(); @@ -566,6 +574,7 @@ void StartLevel(GAMEOPTIONS *gameOptions) gSecretMgr.Clear(); gLevelTime = 0; automapping = 1; + for (int i = 0; i < kMaxSprites; i++) { spritetype *pSprite = &sprite[i]; @@ -579,9 +588,6 @@ void StartLevel(GAMEOPTIONS *gameOptions) DeleteSprite(i); continue; } - - if (sprite[i].lotag == kGDXDudeTargetChanger) - InsertSpriteStat(i, kStatGDXDudeTargetChanger); } } scrLoadPLUs(); @@ -611,7 +617,7 @@ void StartLevel(GAMEOPTIONS *gameOptions) } InitSectorFX(); warpInit(); - actInit(); + actInit(false); evInit(); for (int i = connecthead; i >= 0; i = connectpoint2[i]) { @@ -1517,14 +1523,14 @@ int app_main(int argc, char const * const * argv) Resource::heap = new QHeap(nMaxAlloc); #endif gSysRes.Init(pUserRFF ? pUserRFF : "BLOOD.RFF"); - gGuiRes.Init("GUI.RFF"); + //gGuiRes.Init("GUI.RFF"); gSoundRes.Init(pUserSoundRFF ? pUserSoundRFF : "SOUNDS.RFF"); HookReplaceFunctions(); initprintf("Initializing Build 3D engine\n"); scrInit(); - + initprintf("Loading tiles\n"); if (pUserTiles) { diff --git a/source/blood/src/blood.h b/source/blood/src/blood.h index f557a96d0..ff922b917 100644 --- a/source/blood/src/blood.h +++ b/source/blood/src/blood.h @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "levels.h" #include "resource.h" +#include "db.h" struct INIDESCRIPTION { const char *pzName; diff --git a/source/blood/src/callback.cpp b/source/blood/src/callback.cpp index 4043bae4c..47ff1c568 100644 --- a/source/blood/src/callback.cpp +++ b/source/blood/src/callback.cpp @@ -44,6 +44,62 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "triggers.h" #include "view.h" +void makeMissileBlocking(int nSprite) // 23 +{ + dassert(nSprite >= 0 && nSprite < kMaxSprites); + if (sprite[nSprite].statnum != 5) return; + sprite[nSprite].cstat |= CSTAT_SPRITE_BLOCK; +} + +void UniMissileBurst(int nSprite) // 22 +{ + dassert(nSprite >= 0 && nSprite < kMaxSprites); + if (sprite[nSprite].statnum != 5) return; + spritetype * pSprite = &sprite[nSprite]; + int nAngle = getangle(xvel[nSprite], yvel[nSprite]); + int nRadius = 0x55555; + + for (int i = 0; i < 8; i++) + { + spritetype* pBurst = actSpawnSprite(pSprite, 5); + + pBurst->lotag = pSprite->lotag; + pBurst->shade = pSprite->shade; + pBurst->picnum = pSprite->picnum; + + pBurst->cstat = pSprite->cstat; + if ((pBurst->cstat & CSTAT_SPRITE_BLOCK)) { + pBurst->cstat &= ~CSTAT_SPRITE_BLOCK; // we don't want missiles impact each other + evPost(pBurst->xvel, 3, 100, CALLBACK_ID_23); // so set blocking flag a bit later + } + + pBurst->pal = pSprite->pal; + pBurst->clipdist = pSprite->clipdist / 4; + pBurst->hitag = pSprite->hitag; + pBurst->xrepeat = pSprite->xrepeat / 2; + pBurst->yrepeat = pSprite->yrepeat / 2; + pBurst->ang = ((pSprite->ang + missileInfo[pSprite->lotag - kMissileBase].at6) & 2047); + pBurst->owner = pSprite->owner; + + actBuildMissile(pBurst, pBurst->extra, pSprite->xvel); + + int nAngle2 = (i << 11) / 8; + int dx = 0; + int dy = mulscale30r(nRadius, Sin(nAngle2)); + int dz = mulscale30r(nRadius, -Cos(nAngle2)); + if (i & 1) + { + dy >>= 1; + dz >>= 1; + } + RotateVector(&dx, &dy, nAngle); + xvel[pBurst->index] += dx; + yvel[pBurst->index] += dy; + zvel[pBurst->index] += dz; + evPost(pBurst->index, 3, 960, CALLBACK_ID_1); + } + evPost(nSprite, 3, 0, CALLBACK_ID_1); +} void sub_74C20(int nSprite) // 7 { @@ -730,5 +786,7 @@ void(*gCallback[kCallbackMax])(int) = sub_768E8, sub_766B8, sub_769B4, - sub_76B78 + sub_76B78, + UniMissileBurst, + makeMissileBlocking, }; diff --git a/source/blood/src/callback.h b/source/blood/src/callback.h index c6ad73654..4f89099c3 100644 --- a/source/blood/src/callback.h +++ b/source/blood/src/callback.h @@ -47,6 +47,8 @@ enum CALLBACK_ID { CALLBACK_ID_19, CALLBACK_ID_20, CALLBACK_ID_21, + CALLBACK_ID_22, // by NoOne: UniMissileBurst(); + CALLBACK_ID_23, // by NoOne: makeMissileBlocking(); kCallbackMax }; diff --git a/source/blood/src/common_game.h b/source/blood/src/common_game.h index 9465939aa..dc1ff31c7 100644 --- a/source/blood/src/common_game.h +++ b/source/blood/src/common_game.h @@ -83,12 +83,13 @@ void QuitGame(void); #define kMissileBase 300 #define kMissileMax 318 #define kThingBase 400 -#define kThingMax 435 +#define kThingMax 436 -#define kMaxPowerUps 49 +#define kMaxPowerUps 51 #define kStatRespawn 8 #define kStatMarker 10 +#define kStatGDXDudeTargetChanger 20 #define kStatFree 1024 #define kLensSize 80 @@ -103,7 +104,7 @@ void QuitGame(void); #define kItemBase 100 #define kWeaponItemBase 40 -#define kItemMax 149 +#define kItemMax 151 // marker sprite types #define kMarkerSPStart 1 @@ -122,16 +123,26 @@ void QuitGame(void); #define kMarkerLowGoo 14 #define kMarkerPath 15 - // sprite attributes -#define kHitagMovePhys 0x0001 // affected by movement physics -#define kHitagGravityPhys 0x0002 // affected by gravity -#define kHitagFalling 0x0004 // currently in z-motion #define kHitagAutoAim 0x0008 #define kHitagRespawn 0x0010 #define kHitagFree 0x0020 #define kHitagSmoke 0x0100 -#define kHitagExtBit 0x8000 // NoOne's extension bit(Note: it's bit 0 in editor!) + +// sprite physics attributes +#define kPhysMove 0x0001 // affected by movement physics +#define kPhysGravity 0x0002 // affected by gravity +#define kPhysFalling 0x0004 // currently in z-motion +// additional physics attributes for debris sprites +#define kPhysDebrisFly 0x0008 // *debris* affected by negative gravity (fly instead of falling, DO NOT mess with kHitagAutoAim) +#define kPhysDebrisVector 0x0400 // *debris* can be affected by vector weapons +#define kPhysDebrisExplode 0x0800 // *debris* can be affected by explosions + +// *modern types only hitag* +#define kModernTypeFlag0 0x0 +#define kModernTypeFlag1 0x1 +#define kModernTypeFlag2 0x2 +#define kModernTypeFlag3 0x3 // sector types #define kSecBase 600 @@ -187,14 +198,18 @@ void QuitGame(void); #define kGDXSectorFXChanger 34 #define kGDXObjDataChanger 35 #define kGDXSpriteDamager 36 -// 37 reserved +#define kGDXObjDataAccumulator 37 #define kGDXEffectSpawner 38 #define kGDXWindGenerator 39 +#define kModernConcussSprite 712 #define kGDXThingTNTProx 433 // detects only players #define kGDXThingThrowableRock 434 // does small damage if hits target -#define kGDXDudeUniversalCultist 254 -#define kGDXGenDudeBurning 255 +#define kGDXThingCustomDudeLifeLeech 435 // the same as normal, except it aims in specified target +#define kCustomDude 254 +#define kCustomDudeBurning 255 + +#define kGDXItemMapLevel 150 // once picked up, draws whole minimap // ai state types #define kAiStateOther -1 @@ -536,18 +551,18 @@ inline int approxDist(int dx, int dy) class Rect { public: - int x1, y1, x2, y2; - Rect(int _x1, int _y1, int _x2, int _y2) + int x0, y0, x1, y1; + Rect(int _x0, int _y0, int _x1, int _y1) { - x1 = _x1; y1 = _y1; x2 = _x2; y2 = _y2; + x0 = _x0; y0 = _y0; x1 = _x1; y1 = _y1; } bool isValid(void) const { - return x1 < x2 && y1 < y2; + return x0 < x1 && y0 < y1; } char isEmpty(void) const { - return !(x1 < x2 && y1 < y2); + return !isValid(); } bool operator!(void) const { @@ -556,12 +571,40 @@ public: Rect & operator&=(Rect &pOther) { - x1 = ClipLow(x1, pOther.x1); - y1 = ClipLow(y1, pOther.y1); - x2 = ClipHigh(x2, pOther.x2); - y2 = ClipHigh(y2, pOther.y2); + x0 = ClipLow(x0, pOther.x0); + y0 = ClipLow(y0, pOther.y0); + x1 = ClipHigh(x1, pOther.x1); + y1 = ClipHigh(y1, pOther.y1); return *this; } + + void offset(int dx, int dy) + { + x0 += dx; + y0 += dy; + x1 += dx; + y1 += dy; + } + + int height() + { + return y1 - y0; + } + + int width() + { + return x1 - x0; + } + + bool inside(Rect& other) + { + return (x0 <= other.x0 && x1 >= other.x1 && y0 <= other.y0 && y1 >= other.y1); + } + + bool inside(int x, int y) + { + return (x0 <= x && x1 > x && y0 <= y && y1 > y); + } }; class BitReader { diff --git a/source/blood/src/config.cpp b/source/blood/src/config.cpp index ffa84b16f..b7cb05803 100644 --- a/source/blood/src/config.cpp +++ b/source/blood/src/config.cpp @@ -69,6 +69,7 @@ int32_t JoystickAnalogueSaturate[MAXJOYAXES]; uint8_t KeyboardKeys[NUMGAMEFUNCTIONS][2]; int32_t scripthandle; int32_t setupread; +int32_t MusicRestartsOnLoadToggle; int32_t configversion; int32_t CheckForUpdates; int32_t LastUpdateCheck; @@ -112,6 +113,10 @@ int32_t gFov; int32_t gCenterHoriz; int32_t gDeliriumBlur; +////////// +int gWeaponsV10x; +///////// + int32_t CONFIG_FunctionNameToNum(const char *func) { int32_t i; @@ -668,18 +673,18 @@ int CONFIG_ReadSetup(void) if (scripthandle < 0) { - if (buildvfs_exists(SetupFilename)) // JBF 20031211 - scripthandle = SCRIPT_Load(SetupFilename); + if (buildvfs_exists(SetupFilename)) // JBF 20031211 + scripthandle = SCRIPT_Load(SetupFilename); #if !defined(EDUKE32_TOUCH_DEVICES) && !defined(EDUKE32_STANDALONE) - else if (buildvfs_exists(SETUPFILENAME)) - { - int const i = wm_ynbox("Import Configuration Settings", - "The configuration file \"%s\" was not found. " - "Import configuration data from \"%s\"?", - SetupFilename, SETUPFILENAME); - if (i) - scripthandle = SCRIPT_Load(SETUPFILENAME); - } + else if (buildvfs_exists(SETUPFILENAME)) + { + int const i = wm_ynbox("Import Configuration Settings", + "The configuration file \"%s\" was not found. " + "Import configuration data from \"%s\"?", + SetupFilename, SETUPFILENAME); + if (i) + scripthandle = SCRIPT_Load(SETUPFILENAME); + } #endif } @@ -688,6 +693,11 @@ int CONFIG_ReadSetup(void) if (scripthandle < 0) return -1; + // Nuke: make cvar + /////// + SCRIPT_GetNumber(scripthandle, "Game Options", "WeaponsV10x", &gWeaponsV10x); + /////// + char commmacro[] = "CommbatMacro# "; for (int i = 0; i < MAXRIDECULE; i++) @@ -995,6 +1005,10 @@ void CONFIG_WriteSetup(uint32_t flags) SCRIPT_PutString(scripthandle, "Comm Setup",commmacro,&CommbatMacro[dummy][0]); } + /////// + SCRIPT_PutNumber(scripthandle, "Game Options", "WeaponsV10x", gWeaponsV10x, FALSE, FALSE); + /////// + SCRIPT_Save(scripthandle, SetupFilename); if ((flags & 2) == 0) diff --git a/source/blood/src/config.h b/source/blood/src/config.h index 083fc092c..79751b8db 100644 --- a/source/blood/src/config.h +++ b/source/blood/src/config.h @@ -50,6 +50,7 @@ extern int32_t JoystickAnalogueSaturate[MAXJOYAXES]; extern uint8_t KeyboardKeys[NUMGAMEFUNCTIONS][2]; extern int32_t scripthandle; extern int32_t setupread; +extern int32_t MusicRestartsOnLoadToggle; extern int32_t configversion; extern int32_t CheckForUpdates; extern int32_t LastUpdateCheck; @@ -87,10 +88,16 @@ extern bool gFullMap; extern hashtable_t h_gamefuncs; extern int32_t gUpscaleFactor; extern int32_t gLevelStats; +extern int32_t gPowerupDuration; +extern int32_t gShowMapTitle; extern int32_t gFov; extern int32_t gCenterHoriz; extern int32_t gDeliriumBlur; +/////// +extern int gWeaponsV10x; +////// + int CONFIG_ReadSetup(void); void CONFIG_WriteSetup(uint32_t flags); void CONFIG_SetDefaults(void); diff --git a/source/blood/src/controls.cpp b/source/blood/src/controls.cpp index e85431bd3..3a7d9b4a8 100644 --- a/source/blood/src/controls.cpp +++ b/source/blood/src/controls.cpp @@ -187,8 +187,8 @@ void ctrlGetInput(void) CONTROL_GetInput(&info); - if (MouseDeadZone) - { + if (MouseDeadZone) + { if (info.mousey > 0) info.mousey = max(info.mousey - MouseDeadZone, 0); else if (info.mousey < 0) @@ -198,15 +198,15 @@ void ctrlGetInput(void) info.mousex = max(info.mousex - MouseDeadZone, 0); else if (info.mousex < 0) info.mousex = min(info.mousex + MouseDeadZone, 0); - } + } - if (MouseBias) - { + if (MouseBias) + { if (klabs(info.mousex) > klabs(info.mousey)) info.mousey = tabledivide32_noinline(info.mousey, MouseBias); else info.mousex = tabledivide32_noinline(info.mousex, MouseBias); - } + } if (gQuitRequest) gInput.keyFlags.quit = 1; diff --git a/source/blood/src/credits.cpp b/source/blood/src/credits.cpp index 96dc68ebd..9d318c974 100644 --- a/source/blood/src/credits.cpp +++ b/source/blood/src/credits.cpp @@ -168,6 +168,7 @@ int credKOpen4Load(char *&pzFile) void credPlaySmk(const char *_pzSMK, const char *_pzWAV, int nWav) { + return; #if 0 CSMKPlayer smkPlayer; if (dword_148E14 >= 0) diff --git a/source/blood/src/db.cpp b/source/blood/src/db.cpp index 526ab5a58..93902da09 100644 --- a/source/blood/src/db.cpp +++ b/source/blood/src/db.cpp @@ -519,6 +519,8 @@ void dbXWallClean(void) void dbXSectorClean(void) { + + for (int i = 0; i < numsectors; i++) { int nXSector = sector[i].extra; @@ -1038,7 +1040,7 @@ int dbLoadMap(const char *pPath, int *pX, int *pY, int *pZ, short *pAngle, short pXWall->key = bitReader.readUnsigned(3); pXWall->triggerPush = bitReader.readUnsigned(1); pXWall->triggerVector = bitReader.readUnsigned(1); - pXWall->triggerReserved = bitReader.readUnsigned(1); + pXWall->triggerTouch = bitReader.readUnsigned(1); pXWall->at11_0 = bitReader.readUnsigned(2); pXWall->xpanFrac = bitReader.readUnsigned(8); pXWall->ypanFrac = bitReader.readUnsigned(8); @@ -1077,12 +1079,6 @@ int dbLoadMap(const char *pPath, int *pX, int *pY, int *pZ, short *pAngle, short pSprite->hitag = B_LITTLE16(pSprite->hitag); pSprite->extra = B_LITTLE16(pSprite->extra); #endif - // NoOne's extension bit - if (pSprite->hitag&1) - { - pSprite->hitag &= ~1; - pSprite->hitag |= kHitagExtBit; - } InsertSpriteSect(i, sprite[i].sectnum); InsertSpriteStat(i, sprite[i].statnum); Numsprites++; @@ -1284,8 +1280,8 @@ int dbLoadMap(const char *pPath, int *pX, int *pY, int *pZ, short *pAngle, short int dbSaveMap(const char *pPath, int nX, int nY, int nZ, short nAngle, short nSector) { - char sMapExt[_MAX_PATH]; - char sBakExt[_MAX_PATH]; + char sMapExt[BMAX_PATH]; + char sBakExt[BMAX_PATH]; int16_t tpskyoff[256]; int nSpriteNum; psky_t *pSky = tileSetupSky(0); @@ -1527,7 +1523,7 @@ int dbSaveMap(const char *pPath, int nX, int nY, int nZ, short nAngle, short nSe bitWriter.write(pXWall->key, 3); bitWriter.write(pXWall->triggerPush, 1); bitWriter.write(pXWall->triggerVector, 1); - bitWriter.write(pXWall->triggerReserved, 1); + bitWriter.write(pXWall->triggerTouch, 1); bitWriter.write(pXWall->at11_0, 2); bitWriter.write(pXWall->xpanFrac, 8); bitWriter.write(pXWall->ypanFrac, 8); diff --git a/source/blood/src/db.h b/source/blood/src/db.h index 2719b52ce..4eee7c83e 100644 --- a/source/blood/src/db.h +++ b/source/blood/src/db.h @@ -26,6 +26,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define kMaxXWalls 512 #define kMaxXSectors 512 +// by NoOne additional non-thing proximity, sight and physics sprites +#define kMaxSuperXSprites 128 + #pragma pack(push, 1) struct AISTATE; @@ -52,14 +55,14 @@ struct XSPRITE { unsigned int respawnPending : 2; // respawnPending - signed int dropMsg : 10; // Drop Item + signed int dropMsg : 8; // Drop Item unsigned int Decoupled : 1; // Decoupled unsigned int triggerOnce : 1; // 1-shot unsigned int isTriggered : 1; // works in case if triggerOnce selected unsigned int key : 3; // Key unsigned int wave : 2; // Wave - unsigned int Push: 1; // Push + unsigned int Push : 1; // Push unsigned int Vector : 1; // Vector unsigned int Impact : 1; // Impact unsigned int Pickup : 1; // Pickup @@ -95,9 +98,9 @@ struct XSPRITE { signed int burnSource : 16; unsigned int height : 16; unsigned int stateTimer : 16; // ai timer - AISTATE *aiState; // ai - signed int txIndex : 10; // used by kGDXSequentialTX to keep current TX ID index - signed int cumulDamage : 16; // for dudes + AISTATE* aiState; // ai + signed int sysData1 : 16; // used to keep here various system data, so user can't change it in map editor + unsigned int physAttr : 12; // currently used by additional physics sprites to keep it's attributes. signed int scale; // used for scaling SEQ size on sprites }; @@ -207,7 +210,7 @@ struct XWALL { unsigned int key : 3; // Key unsigned int triggerPush : 1; // Push unsigned int triggerVector : 1; // Vector - unsigned int triggerReserved : 1; // Reserved + unsigned int triggerTouch : 1; // by NoOne: renamed from Reserved to Touch as it works with Touch now. unsigned int at11_0 : 2; // unused unsigned int xpanFrac : 8; // x panning frac unsigned int ypanFrac : 8; // y panning frac diff --git a/source/blood/src/dude.cpp b/source/blood/src/dude.cpp index a282da9c1..9c110c563 100644 --- a/source/blood/src/dude.cpp +++ b/source/blood/src/dude.cpp @@ -750,7 +750,7 @@ DUDEINFO dudeInfo[kDudeMax-kDudeBase] = 0, 0, 7, -1, -1, - 128, 256, 128, 256, 128, 128, 256, + 256, 256, 256, 256, 256, 256, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0 @@ -1554,7 +1554,7 @@ DUDEINFO dudeInfo[kDudeMax-kDudeBase] = // 0, 618, // melee distance 5, // flee health - 12, // hinder damage + 5, // hinder damage 0x0100, // change target chance 0x0010, // change target to kin chance 0x8000, // alertChance diff --git a/source/blood/src/eventq.h b/source/blood/src/eventq.h index fc9d28324..686adcaed 100644 --- a/source/blood/src/eventq.h +++ b/source/blood/src/eventq.h @@ -47,7 +47,6 @@ enum COMMAND_ID { kCommandCallback = 20, COMMAND_ID_21, kGDXCommandPaste = 53, // used by some new GDX types - kGDXCommandSpriteDamage, // used by sprite damager GDX type COMMAND_ID_64 = 64, }; diff --git a/source/blood/src/fx.cpp b/source/blood/src/fx.cpp index 30ee66b86..2ead31993 100644 --- a/source/blood/src/fx.cpp +++ b/source/blood/src/fx.cpp @@ -79,9 +79,9 @@ FXDATA gFXData[] = { { CALLBACK_ID_NONE, 1, 0, 3, 58254, 1024, 480, 3269, 32, 32, 0, 0, 0 }, { CALLBACK_ID_NONE, 1, 0, 3, 58254, 1024, 480, 3273, 32, 32, 0, 0, 0 }, { CALLBACK_ID_NONE, 1, 0, 3, 58254, 1024, 480, 3277, 32, 32, 0, 0, 0 }, - { CALLBACK_ID_NONE, 2, 0, 1, -27962, 8192, 600, 1128, 16, 16, 514, -16, 0 }, - { CALLBACK_ID_NONE, 2, 0, 1, -18641, 8192, 600, 1128, 12, 12, 514, -16, 0 }, - { CALLBACK_ID_NONE, 2, 0, 1, -9320, 8192, 600, 1128, 8, 8, 514, -16, 0 }, + { CALLBACK_ID_NONE, 2, 0, 1, -27962, 8192, 600, 1128, 16, 16, 514, -16, 0 }, // bubble 1 + { CALLBACK_ID_NONE, 2, 0, 1, -18641, 8192, 600, 1128, 12, 12, 514, -16, 0 }, // bubble 2 + { CALLBACK_ID_NONE, 2, 0, 1, -9320, 8192, 600, 1128, 8, 8, 514, -16, 0 }, // bubble 3 { CALLBACK_ID_NONE, 2, 0, 1, -18641, 8192, 600, 1131, 32, 32, 514, -16, 0 }, { CALLBACK_ID_14, 2, 0, 3, 27962, 4096, 480, 733, 32, 32, 0, -16, 0 }, { CALLBACK_ID_NONE, 1, 0, 3, 18641, 4096, 120, 2261, 12, 12, 0, -128, 0 }, diff --git a/source/blood/src/gamemenu.cpp b/source/blood/src/gamemenu.cpp index 3494417d6..0119220cc 100644 --- a/source/blood/src/gamemenu.cpp +++ b/source/blood/src/gamemenu.cpp @@ -830,12 +830,14 @@ bool CGameMenuItem7EA1C::Event(CGameMenuEvent &event) if (at24) delete at24; at24 = new CGameMenu(1); + /* DICTNODE *pRes = gGuiRes.Lookup(at38, "MNU"); if (pRes) { at34 = new IniFile(gGuiRes.Load(pRes)); Setup(); } + */ if (at24) gGameMenuMgr.Push(at24, at28); return false; @@ -2891,7 +2893,7 @@ void CGameMenuItemPassword::Draw(void) gMenuTextMgr.GetFontInfo(m_nFont, kInvalidPasswordMsg, &width, NULL); gMenuTextMgr.DrawText(kInvalidPasswordMsg, m_nFont, m_nX - width / 2, m_nY + 20, shade, 0, false); } - if (at5b && totalclock.Ticks() -at5b > 256) + if (at5b && totalclock-at5b > 256) { at5b = 0; at37 = 0; diff --git a/source/blood/src/levels.h b/source/blood/src/levels.h index 4d5529677..02ace75b8 100644 --- a/source/blood/src/levels.h +++ b/source/blood/src/levels.h @@ -54,6 +54,7 @@ struct GAMEOPTIONS { int nWeaponRespawnTime; int nItemRespawnTime; int nSpecialRespawnTime; + int weaponsV10x; bool bFriendlyFire; bool bKeepKeysOnRespawn; }; diff --git a/source/blood/src/loadsave.cpp b/source/blood/src/loadsave.cpp index 216c42565..99941ebf7 100644 --- a/source/blood/src/loadsave.cpp +++ b/source/blood/src/loadsave.cpp @@ -313,6 +313,7 @@ void MyLoadSave::Load(void) Read(&numyaxbunches, sizeof(numyaxbunches)); #endif gCheatMgr.sub_5BCF4(); + } void MyLoadSave::Save(void) diff --git a/source/blood/src/loadsave.h b/source/blood/src/loadsave.h index 0f8c79c57..03c164d68 100644 --- a/source/blood/src/loadsave.h +++ b/source/blood/src/loadsave.h @@ -54,7 +54,6 @@ public: extern unsigned int gSavedOffset; extern GAMEOPTIONS gSaveGameOptions[]; extern char *gSaveGamePic[10]; - void UpdateSavedInfo(int nSlot); void LoadSavedInfo(void); void LoadSaveSetup(void); diff --git a/source/blood/src/menu.cpp b/source/blood/src/menu.cpp index ee64f40e8..1c8bf1196 100644 --- a/source/blood/src/menu.cpp +++ b/source/blood/src/menu.cpp @@ -76,6 +76,8 @@ void UpdateVideoModeMenuFrameLimit(CGameMenuItemZCycle *pItem); void UpdateVideoModeMenuFPSOffset(CGameMenuItemSlider *pItem); void UpdateVideoColorMenu(CGameMenuItemSliderFloat *); void ResetVideoColor(CGameMenuItemChain *); +void SetWeaponsV10X(CGameMenuItemZBool* pItem); + #ifdef USE_OPENGL void SetupVideoPolymostMenu(CGameMenuItemChain *); #endif @@ -391,6 +393,11 @@ void SetShowMapTitle(CGameMenuItemZBool*); void SetWeaponSwitch(CGameMenuItemZCycle *pItem); CGameMenuItemTitle itemOptionsGameTitle("GAME SETUP", 1, 160, 20, 2038); + +/////////////// +CGameMenuItemZBool itemOptionsGameBoolWeaponsV10X("V1.0x WEAPONS BALANCE:", 3, 66, 130, 180, gWeaponsV10x, SetWeaponsV10X, NULL, NULL); +/////////////////// + CGameMenuItemZBool itemOptionsGameBoolShowWeapons("SHOW WEAPONS:", 3, 66, 70, 180, gShowWeapon, SetShowWeapons, NULL, NULL); CGameMenuItemZBool itemOptionsGameBoolSlopeTilting("SLOPE TILTING:", 3, 66, 80, 180, gSlopeTilting, SetSlopeTilting, NULL, NULL); CGameMenuItemZBool itemOptionsGameBoolViewBobbing("VIEW BOBBING:", 3, 66, 90, 180, gViewVBobbing, SetViewBobbing, NULL, NULL); @@ -1096,6 +1103,13 @@ void SetupOptionsMenu(void) menuOptionsGame.Add(&itemOptionsGameBoolViewSwaying, false); menuOptionsGame.Add(&itemOptionsGameBoolAutoAim, false); menuOptionsGame.Add(&itemOptionsGameWeaponSwitch, false); + + ////////////////////// + if (gGameOptions.nGameType == 0) { + menuOptionsGame.Add(&itemOptionsGameBoolWeaponsV10X, false); + } + ///////////////////// + //menuOptionsGame.Add(&itemOptionsGameChainParentalLock, false); menuOptionsGame.Add(&itemBloodQAV, false); itemOptionsGameBoolShowWeapons.at20 = gShowWeapon; @@ -1105,6 +1119,10 @@ void SetupOptionsMenu(void) itemOptionsGameBoolAutoAim.m_nFocus = gAutoAim; itemOptionsGameWeaponSwitch.m_nFocus = (gWeaponSwitch&1) ? ((gWeaponSwitch&2) ? 1 : 2) : 0; + /////// + itemOptionsGameBoolWeaponsV10X.at20 = gWeaponsV10x; + /////// + menuOptionsDisplay.Add(&itemOptionsDisplayTitle, false); menuOptionsDisplay.Add(&itemOptionsDisplayColor, true); menuOptionsDisplay.Add(&itemOptionsDisplayMode, false); @@ -1365,6 +1383,16 @@ void ResetKeysClassic(CGameMenuItemChain *) CONFIG_SetDefaultKeys(oldkeydefaults); } +//// +void SetWeaponsV10X(CGameMenuItemZBool* pItem) +{ + if (gGameOptions.nGameType == 0) { + gWeaponsV10x = pItem->at20; + gGameOptions.weaponsV10x = pItem->at20; + } +} +//// + void SetShowWeapons(CGameMenuItemZBool *pItem) { gShowWeapon = pItem->at20; @@ -2167,6 +2195,11 @@ void StartNetGame(CGameMenuItemChain *pItem) strncpy(gPacketStartGame.userMapName, itemNetStart10.at20, 13); gPacketStartGame.userMapName[12] = 0; gPacketStartGame.userMap = gPacketStartGame.userMapName[0] != 0; + + //// + gPacketStartGame.weaponsV10x = gWeaponsV10x; + //// + netBroadcastNewGame(); gStartNewGame = 1; gGameMenuMgr.Deactivate(); diff --git a/source/blood/src/network.h b/source/blood/src/network.h index 136efc3ff..6af59b40d 100644 --- a/source/blood/src/network.h +++ b/source/blood/src/network.h @@ -76,6 +76,7 @@ struct PKT_STARTGAME { char episodeId, levelId; int unk; char userMap, userMapName[13]; + int weaponsV10x; bool bFriendlyFire; bool bKeepKeysOnRespawn; }; diff --git a/source/blood/src/player.cpp b/source/blood/src/player.cpp index e282bf86e..a3641384d 100644 --- a/source/blood/src/player.cpp +++ b/source/blood/src/player.cpp @@ -1325,13 +1325,13 @@ char PickupWeapon(PLAYER *pPlayer, spritetype *pWeapon) sfxPlay3DSound(pPlayer->pSprite, 777, -1, 0); return 1; } - if (!actGetRespawnTime(pWeapon)) - return 0; - if (nAmmoType == -1) - return 0; - if (pPlayer->at181[nAmmoType] >= gAmmoInfo[nAmmoType].at0) - return 0; - pPlayer->at181[nAmmoType] = ClipHigh(pPlayer->at181[nAmmoType]+pWeaponItemData->atc, gAmmoInfo[nAmmoType].at0); + + if (!actGetRespawnTime(pWeapon) || nAmmoType == -1 || pPlayer->at181[nAmmoType] >= gAmmoInfo[nAmmoType].at0) return 0; + else if (pWeapon->extra < 0 || xsprite[pWeapon->extra].data1 <= 0 || VanillaMode() || DemoRecordStatus()) + pPlayer->at181[nAmmoType] = ClipHigh(pPlayer->at181[nAmmoType]+pWeaponItemData->atc, gAmmoInfo[nAmmoType].at0); + else + pPlayer->at181[nAmmoType] = ClipHigh(pPlayer->at181[nAmmoType] + xsprite[pWeapon->extra].data1, gAmmoInfo[nAmmoType].at0); + sfxPlay3DSound(pPlayer->pSprite, 777, -1, 0); return 1; } @@ -1342,28 +1342,27 @@ void PickUp(PLAYER *pPlayer, spritetype *pSprite) int nType = pSprite->type; char pickedUp = 0; int customMsg = -1; - if (nType != 40 && nType != 80) { // By NoOne: no pickup for random item generators. - XSPRITE* pXSprite = (pSprite->extra >= 0) ? &xsprite[pSprite->extra] : NULL; - if (pXSprite != NULL && pXSprite->txID != 3 && pXSprite->lockMsg > 0) // by NoOne: allow custom INI message instead "Picked up" - customMsg = pXSprite->lockMsg; + XSPRITE* pXSprite = (pSprite->extra >= 0) ? &xsprite[pSprite->extra] : NULL; + if (pXSprite != NULL && pXSprite->txID != 3 && pXSprite->lockMsg > 0) // by NoOne: allow custom INI message instead "Picked up" + customMsg = pXSprite->lockMsg; - if (nType >= 100 && nType <= 149) - { - pickedUp = PickupItem(pPlayer, pSprite); - if (pickedUp && customMsg == -1) sprintf(buffer, "Picked up %s", gItemText[nType - 100]); - } - else if (nType >= 60 && nType < 81) - { - pickedUp = PickupAmmo(pPlayer, pSprite); - if (pickedUp && customMsg == -1) sprintf(buffer, "Picked up %s", gAmmoText[nType - 60]); - } - else if (nType >= 40 && nType < 51) - { - pickedUp = PickupWeapon(pPlayer, pSprite); - if (pickedUp && customMsg == -1) sprintf(buffer, "Picked up %s", gWeaponText[nType - 40]); - } + if (nType >= 100 && nType <= 149) + { + pickedUp = PickupItem(pPlayer, pSprite); + if (pickedUp && customMsg == -1) sprintf(buffer, "Picked up %s", gItemText[nType - 100]); } + else if (nType >= 60 && nType < 81) + { + pickedUp = PickupAmmo(pPlayer, pSprite); + if (pickedUp && customMsg == -1) sprintf(buffer, "Picked up %s", gAmmoText[nType - 60]); + } + else if (nType >= 40 && nType < 51) + { + pickedUp = PickupWeapon(pPlayer, pSprite); + if (pickedUp && customMsg == -1) sprintf(buffer, "Picked up %s", gWeaponText[nType - 40]); + } + if (pickedUp) { if (pSprite->extra > 0) diff --git a/source/blood/src/replace.cpp b/source/blood/src/replace.cpp index f0f0c24dc..69cd07b3c 100644 --- a/source/blood/src/replace.cpp +++ b/source/blood/src/replace.cpp @@ -36,7 +36,7 @@ int qanimateoffs(int a1, int a2) int frames = picanm[a1].num; if (frames > 0) { - int const frameClock = gFrameClock); + int const frameClock = (int)gFrameClock; int vd; if ((a2&0xc000) == 0x8000) vd = (Bcrc32(&a2, 2, 0)+frameClock)>>(picanm[a1].sf&PICANM_ANIMSPEED_MASK); diff --git a/source/blood/src/sectorfx.cpp b/source/blood/src/sectorfx.cpp index 893edd43e..5b39adbbb 100644 --- a/source/blood/src/sectorfx.cpp +++ b/source/blood/src/sectorfx.cpp @@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "gameutil.h" #include "globals.h" #include "trig.h" +#include "sectorfx.h" char flicker1[] = { 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, @@ -105,8 +106,10 @@ int GetWaveValue(int a, int b, int c) return 0; } -int shadeCount; -short shadeList[512]; +int shadeCount = 0; +short shadeList[kMaxXSectors]; +int panCount = 0; +short panList[kMaxXSectors]; void DoSectorLighting(void) { @@ -251,8 +254,6 @@ void UndoSectorLighting(void) } } -int panCount; -short panList[kMaxXSectors]; short wallPanList[kMaxXWalls]; int wallPanCount; diff --git a/source/blood/src/sectorfx.h b/source/blood/src/sectorfx.h index b1ed0979a..ecdc0e6b9 100644 --- a/source/blood/src/sectorfx.h +++ b/source/blood/src/sectorfx.h @@ -22,6 +22,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //------------------------------------------------------------------------- #pragma once + +extern int shadeCount; +extern short shadeList[kMaxXSectors]; +extern int panCount; +extern short panList[kMaxXSectors]; + void DoSectorLighting(void); void UndoSectorLighting(void); void DoSectorPanning(void); diff --git a/source/blood/src/sfx.cpp b/source/blood/src/sfx.cpp index 230792d5a..74d8dd403 100644 --- a/source/blood/src/sfx.cpp +++ b/source/blood/src/sfx.cpp @@ -346,7 +346,7 @@ void sfxPlay3DSoundCP(spritetype* pSprite, int soundId, int a3, int a4, int pitc pBonkle->at2c = pBonkle->at20; pBonkle->atc = soundId; pBonkle->at8 = hRes; - pBonkle->at1c = (volume <= 0) ? pEffect->relVol : volume; + pBonkle->at1c = ((volume == 0) ? pEffect->relVol : ((volume == -1) ? 0 : ((volume > 255) ? 255 : volume))); pBonkle->at18 = v14; Calc3DValues(pBonkle); int priority = 1; diff --git a/source/blood/src/startgtk.game.cpp b/source/blood/src/startgtk.game.cpp index 997e1a5ad..45603cd3a 100644 --- a/source/blood/src/startgtk.game.cpp +++ b/source/blood/src/startgtk.game.cpp @@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "dynamicgtk.h" #include "blood.h" #include "gtkpixdata.h" +#include "globals.h" enum { diff --git a/source/blood/src/startosx.game.mm b/source/blood/src/startosx.game.mm index 25e0d29cd..8fe8f147c 100644 --- a/source/blood/src/startosx.game.mm +++ b/source/blood/src/startosx.game.mm @@ -11,6 +11,7 @@ #include "build.h" #include "compat.h" #include "baselayer.h" +#include "globals.h" #ifndef MAC_OS_X_VERSION_10_5 # define NSImageScaleNone NSScaleNone diff --git a/source/blood/src/triggers.cpp b/source/blood/src/triggers.cpp index daba08f18..bbaa763d0 100644 --- a/source/blood/src/triggers.cpp +++ b/source/blood/src/triggers.cpp @@ -49,6 +49,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "triggers.h" #include "trig.h" #include "view.h" +#include "sectorfx.h" #include "messages.h" int basePath[kMaxSectors]; @@ -79,7 +80,32 @@ unsigned int GetWaveValue(unsigned int nPhase, int nType) return nPhase; } -char SetSpriteState(int nSprite, XSPRITE *pXSprite, int nState) +char SetSpriteState(int nSprite, XSPRITE* pXSprite, int nState) +{ + if ((pXSprite->busy & 0xffff) == 0 && pXSprite->state == nState) + return 0; + pXSprite->busy = nState << 16; + pXSprite->state = nState; + evKill(nSprite, 3); + if ((sprite[nSprite].hitag & 16) != 0 && sprite[nSprite].type >= kDudeBase && sprite[nSprite].type < kDudeMax) + { + pXSprite->respawnPending = 3; + evPost(nSprite, 3, gGameOptions.nMonsterRespawnTime, CALLBACK_ID_9); + return 1; + } + if (pXSprite->restState != nState && pXSprite->waitTime > 0) + evPost(nSprite, 3, (pXSprite->waitTime * 120) / 10, pXSprite->restState ? COMMAND_ID_1 : COMMAND_ID_0); + if (pXSprite->txID) + { + if (pXSprite->command != 5 && pXSprite->triggerOn && pXSprite->state) + evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); + if (pXSprite->command != 5 && pXSprite->triggerOff && !pXSprite->state) + evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); + } + return 1; +} + +char modernTypeSetSpriteState(int nSprite, XSPRITE *pXSprite, int nState) { if ((pXSprite->busy&0xffff) == 0 && pXSprite->state == nState) return 0; @@ -94,12 +120,26 @@ char SetSpriteState(int nSprite, XSPRITE *pXSprite, int nState) } if (pXSprite->restState != nState && pXSprite->waitTime > 0) evPost(nSprite, 3, (pXSprite->waitTime*120) / 10, pXSprite->restState ? COMMAND_ID_1 : COMMAND_ID_0); - if (pXSprite->txID) - { - if (pXSprite->command != 5 && pXSprite->triggerOn && pXSprite->state) - evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); - if (pXSprite->command != 5 && pXSprite->triggerOff && !pXSprite->state) - evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); + + if (pXSprite->txID != 0 && ((pXSprite->triggerOn && pXSprite->state) || (pXSprite->triggerOff && !pXSprite->state))) { + + // by NoOne: Sending new command instead of link is *required*, because types above + //are universal and can paste properties in different objects. + switch (pXSprite->command) { + case COMMAND_ID_5: + case kGDXCommandPaste: + evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); // just send command to change properties + return 1; + case COMMAND_ID_7: + evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); // send normal command first + evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); // then send command to change properties + return 1; + default: + evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); // send first command to change properties + evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); // then send normal command + return 1; + } + } return 1; } @@ -374,48 +414,45 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT a3) /* - ranged TX ID is now supported also - */ case kGDXRandomTX: { - std::default_random_engine rng; int tx = 0; + std::default_random_engine rng; 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) { // data1 must be less than data4 if (pXSprite->data1 > pXSprite->data4) { - int tmp = pXSprite->data1; - pXSprite->data1 = pXSprite->data4; + short tmp = pXSprite->data1; + pXSprite->data1 = (short) pXSprite->data4; pXSprite->data4 = tmp; } int total = pXSprite->data4 - pXSprite->data1; - int data1 = pXSprite->data1; int result = 0; + while (maxRetries > 0) { + + // use true random only for single player mode + // otherwise use Blood's default one. In the future it maybe possible to make + // host send info to clients about what was generated. - // use true random only for single player mode - if (gGameOptions.nGameType == 0 && !VanillaMode() && !DemoRecordStatus()) { - rng.seed(std::random_device()()); - pXSprite->txID = (int)my_random(pXSprite->data1, pXSprite->data4); - - // otherwise use Blood's default one. In the future it maybe possible to make - // host send info to clients about what was generated. - } else { - pXSprite->txID = Random(total) + data1; + if (gGameOptions.nGameType != 0 || VanillaMode() || DemoRecordStatus()) tx = Random(total) + pXSprite->data1; + else { + rng.seed(std::random_device()()); + tx = (int)my_random(pXSprite->data1, pXSprite->data4); + } + + if (tx != pXSprite->txID) break; + maxRetries--; } - } else if ((tx = GetRandDataVal(NULL,pSprite)) > 0) { - pXSprite->txID = tx; + } else { + while (maxRetries > 0) { + if ((tx = GetRandDataVal(NULL, pSprite)) > 0 && tx != pXSprite->txID) break; + maxRetries--; + } } - - switch (a3.cmd) - { - case COMMAND_ID_0: - SetSpriteState(nSprite, pXSprite, 0); - break; - case COMMAND_ID_1: - SetSpriteState(nSprite, pXSprite, 1); - break; - default: + + if (tx > 0) { + pXSprite->txID = tx; SetSpriteState(nSprite, pXSprite, pXSprite->state ^ 1); - break; } - break; } /* - Sequential Switch takes values from data fields starting from data1 and uses it as TX ID - */ @@ -428,79 +465,92 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT a3) // data1 must be less than data4 if (pXSprite->data1 > pXSprite->data4) { - int tmp = pXSprite->data1; - pXSprite->data1 = (short)pXSprite->data4; + short tmp = pXSprite->data1; + pXSprite->data1 = (short) pXSprite->data4; pXSprite->data4 = tmp; } // force send command to all TX id in a range - if (pSprite->hitag == 1) { - for (int i = pXSprite->data1; i <= pXSprite->data4; i++) { - evSend(nSprite, 3, i, (COMMAND_ID) pXSprite->command); + if (pSprite->hitag & kModernTypeFlag1) { + for (pXSprite->txID = pXSprite->data1; pXSprite->txID <= pXSprite->data4; pXSprite->txID++) { + if (pXSprite->txID > 0) + evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); } - pXSprite->txIndex = 0; - SetSpriteState(nSprite, pXSprite, pXSprite->state ^ 1); - break; + pXSprite->txID = pXSprite->sysData1 = 0; + return; } // Make sure txIndex is correct as we store current index of TX ID here. - if (pXSprite->txIndex < pXSprite->data1) pXSprite->txIndex = pXSprite->data1; - else if (pXSprite->txIndex > pXSprite->data4) pXSprite->txIndex = pXSprite->data4; + if (pXSprite->sysData1 < pXSprite->data1) pXSprite->sysData1 = pXSprite->data1; + else if (pXSprite->sysData1 > pXSprite->data4) pXSprite->sysData1 = pXSprite->data4; range = true; } else { + + // force send command to all TX id specified in data + if (pSprite->hitag & kModernTypeFlag1) { + for (int i = 0; i <= 3; i++) { + if ((pXSprite->txID = GetDataVal(pSprite, i)) > 0) + evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); + } + + pXSprite->txID = pXSprite->sysData1 = 0; + return; + } + // Make sure txIndex is correct as we store current index of data field here. - if (pXSprite->txIndex > 3) pXSprite->txIndex = 0; - else if (pXSprite->txIndex < 0) pXSprite->txIndex = 3; + if (pXSprite->sysData1 > 3) pXSprite->sysData1 = 0; + else if (pXSprite->sysData1 < 0) pXSprite->sysData1 = 3; + } switch (a3.cmd) { case COMMAND_ID_0: if (range == false) { while (cnt-- >= 0) { // skip empty data fields - pXSprite->txIndex--; - if (pXSprite->txIndex < 0) pXSprite->txIndex = 3; - tx = GetDataVal(pSprite, pXSprite->txIndex); + pXSprite->sysData1--; + if (pXSprite->sysData1 < 0) pXSprite->sysData1 = 3; + tx = GetDataVal(pSprite, pXSprite->sysData1); if (tx < 0) ThrowError(" -- Current data index is negative"); if (tx > 0) break; continue; } } else { - pXSprite->txIndex--; - if (pXSprite->txIndex < pXSprite->data1) { - pXSprite->txIndex = pXSprite->data4; + pXSprite->sysData1--; + if (pXSprite->sysData1 < pXSprite->data1) { + pXSprite->sysData1 = pXSprite->data4; } - tx = pXSprite->txIndex; + tx = pXSprite->sysData1; } break; default: if (range == false) { while (cnt-- >= 0) { // skip empty data fields - if (pXSprite->txIndex > 3) pXSprite->txIndex = 0; - tx = GetDataVal(pSprite, pXSprite->txIndex); + if (pXSprite->sysData1 > 3) pXSprite->sysData1 = 0; + tx = GetDataVal(pSprite, pXSprite->sysData1); if (tx < 0) ThrowError(" ++ Current data index is negative"); - pXSprite->txIndex++; + pXSprite->sysData1++; if (tx > 0) break; continue; } } else { - tx = pXSprite->txIndex; - if (pXSprite->txIndex >= pXSprite->data4) { - pXSprite->txIndex = pXSprite->data1; + tx = pXSprite->sysData1; + if (pXSprite->sysData1 >= pXSprite->data4) { + pXSprite->sysData1 = pXSprite->data1; break; } - pXSprite->txIndex++; + pXSprite->sysData1++; } break; } - - pXSprite->txID = (short)tx; + + pXSprite->txID = tx; SetSpriteState(nSprite, pXSprite, pXSprite->state ^ 1); - break; } + break; case 413: if (pXSprite->health > 0) { @@ -587,6 +637,31 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT a3) break; } break; + // by NoOne: various modern types + case kMarkerWarpDest: + if (pXSprite->txID <= 0) { + if (SetSpriteState(nSprite, pXSprite, pXSprite->state ^ 1) == 1) + useTeleportTarget(pXSprite, NULL); + break; + } + modernTypeSetSpriteState(nSprite, pXSprite, pXSprite->state ^ 1); + break; + case kGDXSpriteDamager: + if (pXSprite->txID <= 0) { + if (SetSpriteState(nSprite, pXSprite, pXSprite->state ^ 1) == 1) + useSpriteDamager(pXSprite, NULL); + break; + } + modernTypeSetSpriteState(nSprite, pXSprite, pXSprite->state ^ 1); + break; + case kGDXObjPropertiesChanger: + case kGDXObjPicnumChanger: + case kGDXObjSizeChanger: + case kGDXSectorFXChanger: + case kGDXObjDataChanger: + case kModernConcussSprite: + modernTypeSetSpriteState(nSprite, pXSprite, pXSprite->state ^ 1); + break; case 20: switch (a3.cmd) { @@ -640,10 +715,28 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT a3) case kMarkerLowLink: case kMarkerUpStack: case kMarkerLowStack: - case kMarkerPath: if (pXSprite->command == 5 && pXSprite->txID != 0) evSend(nSprite, 3, pXSprite->txID, COMMAND_ID_5); break; + // by NoOne: add triggering sprite feature. Path sector will trigger the marker after + // it gets reached so it can send commands. + case kMarkerPath: + switch (a3.cmd) { + case COMMAND_ID_0: + SetSpriteState(nSprite, pXSprite, 0); + break; + case COMMAND_ID_1: + SetSpriteState(nSprite, pXSprite, 1); + break; + case COMMAND_ID_5: + if (pXSprite->txID != 0) + evSend(nSprite, 3, pXSprite->txID, COMMAND_ID_5); // don't forget linking! + break; + default: + SetSpriteState(nSprite, pXSprite, pXSprite->state ^ 1); + break; + } + break; case 22: switch (a3.cmd) { @@ -666,40 +759,6 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT a3) else SetSpriteState(nSprite, pXSprite, 0); break; - case kGDXObjPropertiesChanger: - case kGDXObjPicnumChanger: - case kGDXObjSizeChanger: - case kGDXSectorFXChanger: - case kGDXObjDataChanger: - // by NoOne: Sending new command instead of link is *required*, because types above - //are universal and can paste properties in different objects. - if (pXSprite->command == COMMAND_ID_5) - evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); - else { - evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); // send first command to change properties - evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID) pXSprite->command); // then send normal command - } - break; - // this type damages sprite with given damageType - case kGDXSpriteDamager: - evSend(nSprite, 3, pXSprite->txID, kGDXCommandSpriteDamage); - break; - case 40: // Random weapon - case 80: // Random ammo - // let's first search for previously dropped items and remove it - if (pXSprite->dropMsg > 0) { - for (short nItem = headspritestat[3]; nItem >= 0; nItem = nextspritestat[nItem]) { - spritetype* pItem = &sprite[nItem]; - if (pItem->lotag == pXSprite->dropMsg && pItem->x == pSprite->x && pItem->y == pSprite->y && pItem->z == pSprite->z) { - gFX.fxSpawn((FX_ID) 29, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0); - deletesprite(nItem); - break; - } - } - } - // then drop item - DropRandomPickupObject(pSprite, pXSprite->dropMsg); - break; case kGDXCustomDudeSpawn: if (gGameOptions.nMonsterSettings && actSpawnCustomDude(pSprite, -1) != NULL) gKillMgr.sub_263E0(1); @@ -778,28 +837,38 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT a3) case kGDXEffectSpawner: switch (a3.cmd) { case COMMAND_ID_0: - SetSpriteState(nSprite, pXSprite, 0); + if (pXSprite->state == 1) SetSpriteState(nSprite, pXSprite, 0); break; case COMMAND_ID_1: - if (pXSprite->state == 1) break; + evKill(nSprite, 3); // queue overflow protect + if (pXSprite->state == 0) SetSpriteState(nSprite, pXSprite, 1); fallthrough__; case COMMAND_ID_21: - SetSpriteState(nSprite, pXSprite, 1); if (pXSprite->txID <= 0) - (pSprite->type == kGDXSeqSpawner) ? useSeqSpawnerGen(pXSprite, NULL) : useEffectGen(pXSprite, NULL); - else if (pXSprite->command == COMMAND_ID_5) - evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); + (pSprite->type == kGDXSeqSpawner) ? useSeqSpawnerGen(pXSprite, 3, pSprite->xvel) : useEffectGen(pXSprite, NULL); else { - evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); - evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID) pXSprite->command); + + switch (pXSprite->command) { + case COMMAND_ID_5: + evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); // just send command to change properties + break; + case COMMAND_ID_7: + evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); // send normal command first + evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); // then send command to change properties + break; + default: + evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); // send first command to change properties + evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); // then send normal command + break; + } + } - + if (pXSprite->busyTime > 0) evPost(nSprite, 3, ClipLow((int(pXSprite->busyTime) + Random2(pXSprite->data1)) * 120 / 10, 0), COMMAND_ID_21); break; - - case COMMAND_ID_3: - if (pXSprite->state == 0) evPost(nSprite, 3, 0, COMMAND_ID_21); + default: + if (pXSprite->state == 0) evPost(nSprite, 3, 0, COMMAND_ID_1); else evPost(nSprite, 3, 0, COMMAND_ID_0); break; } @@ -849,26 +918,36 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT a3) switch (a3.cmd) { case COMMAND_ID_0: stopWindOnSectors(pXSprite); - SetSpriteState(nSprite, pXSprite, 0); + if (pXSprite->state == 1) SetSpriteState(nSprite, pXSprite, 0); break; case COMMAND_ID_1: - if (pXSprite->state == 1) break; + evKill(nSprite, 3); // queue overflow protect + if (pXSprite->state == 0) SetSpriteState(nSprite, pXSprite, 1); fallthrough__; case COMMAND_ID_21: - SetSpriteState(nSprite, pXSprite, 1); if (pXSprite->txID <= 0) useSectorWindGen(pXSprite, NULL); - else if (pXSprite->command == COMMAND_ID_5) - evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); else { - evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); - evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID) pXSprite->command); + + switch (pXSprite->command) { + case COMMAND_ID_5: + evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); // just send command to change properties + break; + case COMMAND_ID_7: + evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); // send normal command first + evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); // then send command to change properties + break; + default: + evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); // send first command to change properties + evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); // then send normal command + break; + } + } - if (pXSprite->busyTime > 0) - evPost(nSprite, 3, pXSprite->busyTime, COMMAND_ID_21); + if (pXSprite->busyTime > 0) evPost(nSprite, 3, pXSprite->busyTime, COMMAND_ID_21); break; - case COMMAND_ID_3: - if (pXSprite->state == 0) evPost(nSprite, 3, 0, COMMAND_ID_21); + default: + if (pXSprite->state == 0) evPost(nSprite, 3, 0, COMMAND_ID_1); else evPost(nSprite, 3, 0, COMMAND_ID_0); break; } @@ -889,28 +968,38 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT a3) { case COMMAND_ID_0: if (pXSprite->data4 == 3 && activated == false) activateDudes(pXSprite->txID); - SetSpriteState(nSprite, pXSprite, 0); + if (pXSprite->state == 1) SetSpriteState(nSprite, pXSprite, 0); break; case COMMAND_ID_1: - if (pXSprite->state == 1) break; + evKill(nSprite, 3); // queue overflow protect + if (pXSprite->state == 0) SetSpriteState(nSprite, pXSprite, 1); fallthrough__; case COMMAND_ID_21: - SetSpriteState(nSprite, pXSprite, 1); if (pXSprite->txID <= 0 || !getDudesForTargetChg(pXSprite)) { evPost(nSprite, 3, 0, COMMAND_ID_0); break; - } - else if (pXSprite->command == COMMAND_ID_5) - evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); - else { - evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); - evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); + } else { + + switch (pXSprite->command) { + case COMMAND_ID_5: + evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); // just send command to change properties + break; + case COMMAND_ID_7: + evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); // send normal command first + evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); // then send command to change properties + break; + default: + evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); // send first command to change properties + evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); // then send normal command + break; + } + } if (pXSprite->busyTime > 0) evPost(nSprite, 3, pXSprite->busyTime, COMMAND_ID_21); break; - case COMMAND_ID_3: - if (pXSprite->state == 0) evPost(nSprite, 3, 0, COMMAND_ID_21); + default: + if (pXSprite->state == 0) evPost(nSprite, 3, 0, COMMAND_ID_1); else evPost(nSprite, 3, 0, COMMAND_ID_0); break; } @@ -921,12 +1010,13 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT a3) case kGDXObjDataAccumulator: switch (a3.cmd) { case COMMAND_ID_0: - SetSpriteState(nSprite, pXSprite, 0); + if (pXSprite->state == 1) SetSpriteState(nSprite, pXSprite, 0); break; case COMMAND_ID_1: - if (pXSprite->state == 1) break; + evKill(nSprite, 3); // queue overflow protect + if (pXSprite->state == 0) SetSpriteState(nSprite, pXSprite, 1); + fallthrough__; case COMMAND_ID_21: - SetSpriteState(nSprite, pXSprite, 1); // force OFF after *all* TX objects reach the goal value if (pSprite->hitag == 0 && goalValueIsReached(pXSprite)) { @@ -934,29 +1024,77 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT a3) break; } - if (pXSprite->data1 > 0 && pXSprite->data1 <= 4 && pXSprite->data2 > 0) { - if (pXSprite->txID != 0) { - if (pXSprite->command == COMMAND_ID_5) - evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); - else { - evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); - evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID) pXSprite->command); - } + if (pXSprite->txID > 0 && pXSprite->data1 > 0 && pXSprite->data1 <= 4) { + + switch (pXSprite->command) { + case COMMAND_ID_5: + evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); // just send command to change properties + break; + case COMMAND_ID_7: + evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); // send normal command first + evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); // then send command to change properties + break; + default: + evSend(nSprite, 3, pXSprite->txID, kGDXCommandPaste); // send first command to change properties + evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); // then send normal command + break; } + if (pXSprite->busyTime > 0) evPost(nSprite, 3, pXSprite->busyTime, COMMAND_ID_21); } break; - case COMMAND_ID_3: - if (pXSprite->state == 0) evPost(nSprite, 3, 0, COMMAND_ID_21); + default: + if (pXSprite->state == 0) evPost(nSprite, 3, 0, COMMAND_ID_1); else evPost(nSprite, 3, 0, COMMAND_ID_0); break; } break; + case 704: // ecto skull gen + switch (a3.cmd) { + case COMMAND_ID_0: + if (pXSprite->state == 1) SetSpriteState(nSprite, pXSprite, 0); + break; + case COMMAND_ID_1: + evKill(nSprite, 3); // queue overflow protect + if (pXSprite->state == 0) SetSpriteState(nSprite, pXSprite, 1); + fallthrough__; + case COMMAND_ID_21: + ActivateGenerator(nSprite); + if (pXSprite->txID) evSend(nSprite, 3, pXSprite->txID, (COMMAND_ID)pXSprite->command); + if (pXSprite->busyTime > 0) evPost(nSprite, 3, (120 * pXSprite->busyTime) / 10, COMMAND_ID_21); + break; + default: + if (pXSprite->state == 0) evPost(nSprite, 3, 0, COMMAND_ID_1); + else evPost(nSprite, 3, 0, COMMAND_ID_0); + break; + } + break; + + case 40: // Random ammo + case 80: // Random weapon + switch (a3.cmd) { + case COMMAND_ID_0: + if (pXSprite->state == 1) SetSpriteState(nSprite, pXSprite, 0); + break; + case COMMAND_ID_1: + evKill(nSprite, 3); // queue overflow protect + if (pXSprite->state == 0) SetSpriteState(nSprite, pXSprite, 1); + fallthrough__; + case COMMAND_ID_21: + ActivateGenerator(nSprite); + if (pXSprite->busyTime > 0) + evPost(nSprite, 3, (120 * pXSprite->busyTime) / 10, COMMAND_ID_21); + break; + default: + if (pXSprite->state == 0) evPost(nSprite, 3, 0, COMMAND_ID_1); + else evPost(nSprite, 3, 0, COMMAND_ID_0); + break; + } + break; case 700: case 701: case 702: case 703: - case 704: case 705: case 706: case 707: @@ -1035,19 +1173,132 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT a3) // by NoOne: this function stops wind on all TX sectors affected by WindGen after it goes off state. void stopWindOnSectors(XSPRITE* pXSource) { + spritetype* pSource = &sprite[pXSource->reference]; + + if (pXSource->txID <= 0) { + + if (sector[pSource->sectnum].extra >= 0) + xsector[sector[pSource->sectnum].extra].windVel = 0; + + return; + } + for (int i = bucketHead[pXSource->txID]; i < bucketHead[pXSource->txID + 1]; i++) { - if (rxBucket[i].type != 3) continue; + if (rxBucket[i].type != 6) continue; XSECTOR * pXSector = &xsector[sector[rxBucket[i].index].extra]; - if ((pXSector->state == 1 && !pXSector->windAlways) || sprite[pXSource->reference].hitag == 1) + if ((pXSector->state == 1 && !pXSector->windAlways) || (sprite[pXSource->reference].hitag & kModernTypeFlag1)) pXSector->windVel = 0; } } +/// WIP //////////////////////////////////////////////////////// +void useConcussSprite(XSPRITE* pXSource, spritetype* pSprite) { + spritetype* pSource = &sprite[pXSource->reference]; + int nIndex = isDebris(pSprite->index); + //ThrowError("%d", gPhysSpritesList[nIndex]); + //int size = (tilesiz[pSprite->picnum].x * pSprite->xrepeat * tilesiz[pSprite->picnum].y * pSprite->yrepeat) >> 1; + //int t = scale(pXSource->data1, size, gSpriteMass[pSprite->extra].mass); + //xvel[pSprite->xvel] += mulscale16(t, pSprite->x); + //yvel[pSprite->xvel] += mulscale16(t, pSprite->y); + //zvel[pSprite->xvel] += mulscale16(t, pSprite->z); + + //debrisConcuss(pXSource->reference, nIndex, pSprite->x - 100, pSprite->y - 100, pSprite->z - 100, pXSource->data1); +} + +void useTeleportTarget(XSPRITE* pXSource, spritetype* pSprite) { + spritetype* pSource = &sprite[pXSource->reference]; + XSECTOR* pXSector = (sector[pSource->sectnum].extra >= 0) ? &xsector[sector[pSource->sectnum].extra] : NULL; + + if (pSprite == NULL) { + + if (pXSource->data1 > 0) { + for (int i = connecthead; i >= 0; i = connectpoint2[i]) { + + if (pXSource->data1 < kMaxPlayers) // relative to connected players + if (pXSource->data1 != (i + 1)) + continue; + else if (pXSource->data1 < (kDudePlayer1 + kMaxPlayers)) // absolute lotag + if (pXSource->data1 >= kDudePlayer1 && (pXSource->data1 + (kDudePlayer1 - 1)) == gPlayer[i].pSprite->type) + continue; + + useTeleportTarget(pXSource, gPlayer[i].pSprite); + return; + + } + } + + return; + } + + pSprite->x = pSource->x; pSprite->y = pSource->y; + pSprite->z += (sector[pSource->sectnum].floorz - sector[pSprite->sectnum].floorz); + + if (pSource->hitag & kModernTypeFlag1) // force telefrag + TeleFrag(pSprite->xvel, pSource->sectnum); + + changespritesect((short)pSprite->xvel, pSource->sectnum); + if (pXSector != NULL && pXSector->Underwater) xsprite[pSprite->extra].medium = 1; + else xsprite[pSprite->extra].medium = 0; + + if (pXSource->data2 == 1) + pSprite->ang = pSource->ang; + + if (pXSource->data3 == 1) + xvel[pSprite->xvel] = yvel[pSprite->xvel] = zvel[pSprite->xvel] = 0; + + viewBackupSpriteLoc(pSprite->xvel, pSprite); + + if (pXSource->data4 > 0) + sfxPlay3DSound(pSource, pXSource->data4, -1, 0); + + if (IsPlayerSprite(pSprite)) { + + PLAYER* pPlayer = &gPlayer[pSprite->lotag - kDudePlayer1]; + playerResetInertia(pPlayer); + + if (pXSource->data2 == 1) { + pPlayer->at6b = pPlayer->at73 = 0; + } + } +} + + +void useEffectGen(XSPRITE * pXSource, spritetype * pSprite) { + if (pSprite == NULL) pSprite = &sprite[pXSource->reference]; + if (pSprite->extra < 0) return; + + int top, bottom; GetSpriteExtents(pSprite, &top, &bottom); spritetype * pEffect = NULL; + int dx = 0, dy = 0; int cnt = (pXSource->data4 > 32) ? 32 : pXSource->data4; + + while (cnt-- >= 0) { + if (cnt > 0) { + int dx = Random3(250); + int dy = Random3(150); + } + + pEffect = gFX.fxSpawn((FX_ID)pXSource->data2, pSprite->sectnum, pSprite->x + dx, pSprite->y + dy, top, 0); + if (pEffect != NULL) { + + if ((pEffect->cstat & CSTAT_SPRITE_ALIGNMENT_WALL) && (pEffect->cstat & CSTAT_SPRITE_ONE_SIDED)) + pEffect->cstat &= ~CSTAT_SPRITE_ONE_SIDED; + + if (pEffect->pal <= 0) pEffect->pal = pSprite->pal; + if (pEffect->xrepeat <= 0) pEffect->xrepeat = pSprite->xrepeat; + if (pEffect->yrepeat <= 0) pEffect->yrepeat = pSprite->yrepeat; + if (pEffect->shade == 0) pEffect->shade = pSprite->shade; + } + } + + if (pXSource->data3 > 0) + sfxPlay3DSound(pSprite, pXSource->data3, -1, 0); + +} + void useSectorWindGen(XSPRITE* pXSource, sectortype* pSector) { spritetype* pSource = &sprite[pXSource->reference]; - XSECTOR* pXSector = NULL; bool forceWind = false; - + XSECTOR* pXSector = NULL; bool forceWind = false; + int nXSector = 0; if (pSector == NULL) { if (sector[pSource->sectnum].extra < 0) { @@ -1059,9 +1310,12 @@ void useSectorWindGen(XSPRITE* pXSource, sectortype* pSector) { } else { pXSector = &xsector[sector[pSource->sectnum].extra]; + nXSector = sector[pXSector->reference].extra; } + } else { pXSector = &xsector[pSector->extra]; + nXSector = sector[pXSector->reference].extra; } if (pSource->hitag) { @@ -1099,54 +1353,128 @@ void useSectorWindGen(XSPRITE* pXSource, sectortype* pSector) { break; } + short oldPan = pXSector->panVel; pXSector->panAngle = pXSector->windAng; pXSector->panVel = pXSector->windVel; + + // add to panList if panVel was set to 0 previously + if (oldPan == 0 && pXSector->panVel != 0 && panCount < kMaxXSprites) { + + int i; + for (i = 0; i < panCount; i++) { + if (panList[i] != nXSector) continue; + break; + } + + if (i == panCount) + panList[panCount++] = nXSector; + } + } } -void useSeqSpawnerGen(XSPRITE* pXSource, spritetype* pSprite) { - if (pSprite == NULL) pSprite = &sprite[pXSource->reference]; - if (pSprite->extra < 0) return; - - seqSpawn(pXSource->data2, 3, pSprite->extra, (pXSource->data3 > 0) ? pXSource->data3 : -1); - if (pXSource->data4 > 0) - sfxPlay3DSound(pSprite, pXSource->data4, -1, 0); -} +void useSpriteDamager(XSPRITE* pXSource, spritetype* pSprite) { + int dmg = (pXSource->data4 == 0 || pXSource->data4 > 65534) ? 65535 : pXSource->data4; + int dmgType = (pXSource->data3 >= 7) ? Random(6) : ((pXSource->data3 < 0) ? 0 : pXSource->data3); -void useEffectGen(XSPRITE* pXSource, spritetype* pSprite) { - if (pSprite == NULL) pSprite = &sprite[pXSource->reference]; - if (pSprite->extra < 0) return; + // just damage / heal TX ID sprite + if (pSprite != NULL) { + actDamageSprite(pSprite->xvel, pSprite, (DAMAGE_TYPE) dmgType, dmg); + return; - int top, bottom; GetSpriteExtents(pSprite, &top, &bottom); int cnt = pXSource->data4; - spritetype* pEffect = NULL; if (cnt > 32) cnt = 32; + + } // or damage / heal player# specified in data2 (or all players if data2 is empty) + else if (pXSource->data2 > 0 && pXSource->data2 <= kMaxPlayers) { - while (cnt-- >= 0) { - if (cnt > 0) { - - int dx = Random3(250); - int dy = Random3(150); - - pEffect = gFX.fxSpawn((FX_ID)pXSource->data2, pSprite->sectnum, pSprite->x + dx, pSprite->y + dy, top, 0); - - } - else { - pEffect = gFX.fxSpawn((FX_ID)pXSource->data2, pSprite->sectnum, pSprite->x, pSprite->y, top, 0); - } - - if (pEffect != NULL) { - if (pEffect->pal <= 0) pEffect->pal = pSprite->pal; - if (pEffect->xrepeat <= 0) pEffect->xrepeat = pSprite->xrepeat; - if (pEffect->yrepeat <= 0) pEffect->yrepeat = pSprite->yrepeat; - if (pEffect->shade == 0) pEffect->shade = pSprite->shade; + for (int i = connecthead; i >= 0; i = connectpoint2[i]) { + if (pXSource->data1 < kMaxPlayers) // relative to connected players + if (pXSource->data1 != (i + 1)) + continue; + else if (pXSource->data1 < (kDudePlayer1 + kMaxPlayers)) // absolute lotag + if (pXSource->data1 >= kDudePlayer1 && (pXSource->data1 + (kDudePlayer1 - 1)) == gPlayer[i].pSprite->type) + continue; + actDamageSprite(sprite[pXSource->reference].xvel, gPlayer[i].pSprite, (DAMAGE_TYPE) dmgType, dmg); + return; } } - - if (pXSource->data3 > 0) - sfxPlay3DSound(pSprite, pXSource->data3, -1, 0); - } +void useSeqSpawnerGen(XSPRITE* pXSource, int objType, int index) { + switch (objType) { + case 6: + if (pXSource->data2 <= 0) { + if (pXSource->data3 == 3 || pXSource->data3 == 1) + seqKill(2, sector[index].extra); + if (pXSource->data3 == 3 || pXSource->data3 == 2) + seqKill(1, sector[index].extra); + } + else { + if (pXSource->data3 == 3 || pXSource->data3 == 1) + seqSpawn(pXSource->data2, 2, sector[index].extra, -1); + if (pXSource->data3 == 3 || pXSource->data3 == 2) + seqSpawn(pXSource->data2, 1, sector[index].extra, -1); + } + return; + case 0: + if (pXSource->data2 <= 0) { + if (pXSource->data3 == 3 || pXSource->data3 == 1) + seqKill(0, wall[index].extra); + if ((pXSource->data3 == 3 || pXSource->data3 == 2) && (wall[index].cstat & CSTAT_WALL_MASKED)) + seqKill(4, wall[index].extra); + } + else { + + if (pXSource->data3 == 3 || pXSource->data3 == 1) + seqSpawn(pXSource->data2, 0, wall[index].extra, -1); + if (pXSource->data3 == 3 || pXSource->data3 == 2) { + + if (wall[index].nextwall < 0) { + if (pXSource->data3 == 3) + seqSpawn(pXSource->data2, 0, wall[index].extra, -1); + + } + else { + if (!(wall[index].cstat & CSTAT_WALL_MASKED)) + wall[index].cstat |= CSTAT_WALL_MASKED; + + seqSpawn(pXSource->data2, 4, wall[index].extra, -1); + } + } + + if (pXSource->data4 > 0) { + + int cx, cy, cz, wx, wy, wz; + cx = (wall[index].x + wall[wall[index].point2].x) >> 1; + cy = (wall[index].y + wall[wall[index].point2].y) >> 1; + int nSector = sectorofwall(index); + int32_t ceilZ, floorZ; + getzsofslope(nSector, cx, cy, &ceilZ, &floorZ); + int32_t ceilZ2, floorZ2; + getzsofslope(wall[index].nextsector, cx, cy, &ceilZ2, &floorZ2); + ceilZ = ClipLow(ceilZ, ceilZ2); + floorZ = ClipHigh(floorZ, floorZ2); + wz = floorZ - ceilZ; + wx = wall[wall[index].point2].x - wall[index].x; + wy = wall[wall[index].point2].y - wall[index].y; + cz = (ceilZ + floorZ) >> 1; + + sfxPlay3DSound(cx, cy, cz, pXSource->data4, nSector); + + } + + } + return; + + case 3: + if (pXSource->data2 <= 0) seqKill(3, sprite[index].extra); + else { + seqSpawn(pXSource->data2, 3, sprite[index].extra, -1); + if (pXSource->data4 > 0) sfxPlay3DSound(&sprite[index], pXSource->data4, -1, 0); + } + return; + } +} void SetupGibWallState(walltype *pWall, XWALL *pXWall) { @@ -1193,47 +1521,64 @@ void OperateWall(int nWall, XWALL *pXWall, EVENT a3) pXWall->locked ^= 1; return; } - if (GetWallType(nWall) == 511) - { - char bStatus; - switch (a3.cmd) - { - case 1: - case 51: - bStatus = SetWallState(nWall, pXWall, 1); + + switch (pWall->lotag) { + // by NoOne: make 1-Way switch type for walls to work... + case 21: + if (VanillaMode()) break; + switch (a3.cmd) { + case 0: + SetWallState(nWall,pXWall,0); + break; + case 1: + SetWallState(nWall, pXWall, 1); + break; + default: + SetWallState(nWall, pXWall, pXWall->restState ^ 1); + break; + } + return; + case 511: + if (GetWallType(nWall) == 511) { + char bStatus; + switch (a3.cmd) { + case 1: + case 51: + bStatus = SetWallState(nWall, pXWall, 1); + break; + case 0: + bStatus = SetWallState(nWall, pXWall, 0); + break; + default: + bStatus = SetWallState(nWall, pXWall, pXWall->state ^ 1); + break; + } + if (bStatus) { + SetupGibWallState(pWall, pXWall); + if (pXWall->state) { + CGibVelocity vel(100, 100, 250); + int nType = ClipRange(pXWall->data, 0, 31); + if (nType > 0) + GibWall(nWall, (GIBTYPE)nType, &vel); + } + } + return; + } break; + } + + switch (a3.cmd) { case 0: - bStatus = SetWallState(nWall, pXWall, 0); + SetWallState(nWall, pXWall, 0); + break; + case 1: + SetWallState(nWall, pXWall, 1); break; default: - bStatus = SetWallState(nWall, pXWall, pXWall->state^1); + SetWallState(nWall, pXWall, pXWall->state ^ 1); break; - } - if (bStatus) - { - SetupGibWallState(pWall, pXWall); - if (pXWall->state) - { - CGibVelocity vel(100, 100, 250); - int nType = ClipRange(pXWall->data, 0, 31); - if (nType > 0) - GibWall(nWall, (GIBTYPE)nType, &vel); - } - } - return; - } - switch (a3.cmd) - { - case 0: - SetWallState(nWall, pXWall, 0); - break; - case 1: - SetWallState(nWall, pXWall, 1); - break; - default: - SetWallState(nWall, pXWall, pXWall->state ^ 1); - break; } + } void SectorStartSound(int nSector, int nState) @@ -1403,7 +1748,7 @@ void TranslateSector(int nSector, int a2, int a3, int a4, int a5, int a6, int a7 spritetype *pSprite = &sprite[nSprite]; // By NoOne: allow to move markers by sector movements in game if hitag 1 is added in editor. if (pSprite->statnum == 10 || pSprite->statnum == 16) { - if (!(pSprite->hitag&kHitagExtBit)) continue; + if (!(pSprite->hitag & kModernTypeFlag1)) continue; } x = baseSprite[nSprite].x; y = baseSprite[nSprite].y; @@ -1992,6 +2337,11 @@ void OperatePath(unsigned int nSector, XSECTOR *pXSector, EVENT a3) break; } } + + // by NoOne: trigger marker after it gets reached + if (pXSprite2->state != 1) + trTriggerSprite(pSprite2->xvel, pXSprite2, COMMAND_ID_1); + if (nSprite < 0) ThrowError("Unable to find path marker with id #%d", nId); pXSector->at2e_0 = nSprite; @@ -2437,137 +2787,69 @@ void trMessageSprite(unsigned int nSprite, EVENT a2) LinkSprite(nSprite, pXSprite, a2); else if (a2.cmd == kGDXCommandPaste) pastePropertiesInObj(3, nSprite, a2); - else if (a2.cmd == kGDXCommandSpriteDamage) - trDamageSprite(3, nSprite, a2); else OperateSprite(nSprite, pXSprite, a2); } } -// By NoOne: this function damages sprite -void trDamageSprite(int type, int nDest, EVENT event) { - UNREFERENCED_PARAMETER(type); - - /* - damages xsprite via TX ID - */ - /* - data3 = damage type - */ - /* - data4 = damage amount - */ - - if (event.type == 3) { - spritetype* pSource = NULL; pSource = &sprite[event.index]; - XSPRITE* pXSource = &xsprite[pSource->extra]; - if (xsprite[sprite[nDest].extra].health > 0) { - if (pXSource->data4 == 0) - pXSource->data4 = 65535; - - int dmgType = pXSource->data3; - if (pXSource->data3 >= 7) - dmgType = Random(6); - - actDamageSprite(pSource->xvel, &sprite[nDest], (DAMAGE_TYPE) dmgType, pXSource->data4); - } - } -} - bool valueIsBetween(int val, int min, int max) { return (val > min && val < max); } // By NoOne: this function used by various new GDX types. void pastePropertiesInObj(int type, int nDest, EVENT event) { - spritetype* pSource = NULL; pSource = &sprite[event.index]; - if (pSource == NULL || event.type != 3) return; - XSPRITE* pXSource = &xsprite[pSource->extra]; + + if (event.type != 3) return; + spritetype* pSource = &sprite[event.index]; - if (pSource->type == kGDXEffectSpawner) { + if (pSource->extra < 0) return; + XSPRITE* pXSource = &xsprite[pSource->extra]; + + switch (type) { + case 6: + if (sector[nDest].extra < 0) return; + break; + case 0: + if (wall[nDest].extra < 0) return; + break; + case 3: + if (sprite[nDest].extra < 0) return; + break; + default: + return; + } + + if (pSource->type == kModernConcussSprite) { + /* - Concussing any physics affected sprite with give strength - */ + if (type != 3) return; + else if ((sprite[nDest].hitag & kPhysMove) || (sprite[nDest].hitag & kPhysGravity) || isDebris(nDest)) + useConcussSprite(pXSource, &sprite[nDest]); + return; + + } else if (pSource->type == kMarkerWarpDest) { + /* - Allows teleport any sprite from any location to the source destination - */ + useTeleportTarget(pXSource, &sprite[nDest]); + return; + + } else if (pSource->type == kGDXSpriteDamager) { + /* - damages xsprite via TX ID - */ + if (type != 3) return; + else if (xsprite[sprite[nDest].extra].health > 0) useSpriteDamager(pXSource, &sprite[nDest]); + return; + + } if (pSource->type == kGDXEffectSpawner) { /* - Effect Spawner can spawn any effect passed in data2 on it's or txID sprite - */ if (pXSource->data2 < 0 || pXSource->data2 >= kFXMax) return; else if (type == 3) useEffectGen(pXSource, &sprite[nDest]); return; - } else if (pSource->type == kGDXSeqSpawner) { + } + else if (pSource->type == kGDXSeqSpawner) { /* - SEQ Spawner takes data2 as SEQ ID and spawns it on it's or TX ID sprite - */ - if (pXSource->data2 <= 0 || !gSysRes.Lookup(pXSource->data2, "SEQ")) return; - else if (type == 3) useSeqSpawnerGen(pXSource, &sprite[nDest]); + if (pXSource->data2 > 0 && !gSysRes.Lookup(pXSource->data2, "SEQ")) return; + useSeqSpawnerGen(pXSource, type, nDest); return; - - } else if (pSource->type == kGDXObjDataAccumulator) { - /* - Object Data Accumulator allows to perform sum and sub operations in data fields of object - */ - /* - data1 = destination data index - */ - /* - data2 = step value - */ - /* - data3 = min value - */ - /* - data4 = max value - */ - /* - min > max = sub, min < max = sum - */ - - /* - hitag: 0 = force OFF if goal value was reached for all objects - */ - /* - hitag: 2 = force swap min and max if goal value was reached - */ - /* - hitag: 3 = force reset counter - */ - - if (pXSource->data3 < 0) pXSource->data3 = 0; - else if (pXSource->data3 > 32766) pXSource->data3 = 32767; - if (pXSource->data4 < 0) pXSource->data4 = 0; - else if (pXSource->data4 > 32766) pXSource->data4 = 32767; - - long data = getDataFieldOfObject(type, nDest, pXSource->data1); - if (data == -65535) return; - else if (pXSource->data3 < pXSource->data4) { - - if (data < pXSource->data3) data = pXSource->data3; - if (data > pXSource->data4) data = pXSource->data4; - - if ((data += pXSource->data2) >= pXSource->data4) { - switch (pSource->hitag) { - case 0: - case 1: - if (data > pXSource->data4) data = pXSource->data4; - break; - case 2: - { - - if (data > pXSource->data4) data = pXSource->data4; - if (!goalValueIsReached(pXSource)) break; - int tmp = pXSource->data4; - pXSource->data4 = pXSource->data3; - pXSource->data3 = tmp; - - } - break; - case 3: - if (data > pXSource->data4) data = pXSource->data3; - break; - } - } - - } - else if (pXSource->data3 > pXSource->data4) { - - if (data > pXSource->data3) data = pXSource->data3; - if (data < pXSource->data4) data = pXSource->data4; - - if ((data -= pXSource->data2) <= pXSource->data4) { - switch (pSource->hitag) { - case 0: - case 1: - if (data < pXSource->data4) data = pXSource->data4; - break; - case 2: - { - if (data < pXSource->data4) data = pXSource->data4; - int tmp = pXSource->data4; - pXSource->data4 = pXSource->data3; - pXSource->data3 = tmp; - break; - } - case 3: - if (data < pXSource->data4) data = pXSource->data3; - break; - } - } - } - - setDataValueOfObject(type, nDest, pXSource->data1, data); - return; - - } else if (pSource->type == kGDXWindGenerator) { - + } + else if (pSource->type == kGDXWindGenerator) { /* - Wind generator via TX or for current sector if TX ID not specified - */ /* - sprite.ang = sector wind direction - */ /* - data1 = randomness settings - */ @@ -2584,12 +2866,81 @@ void pastePropertiesInObj(int type, int nDest, EVENT event) { /* - 3: pan both - */ /* - hi-tag = 1: force windAlways and panAlways - */ - + if (pXSource->data2 < 0) return; else if (type == 6) useSectorWindGen(pXSource, §or[nDest]); return; + } else if (pSource->type == kGDXObjDataAccumulator) { + /* - Object Data Accumulator allows to perform sum and sub operations in data fields of object - */ + /* - data1 = destination data index - */ + /* - data2 = min value - */ + /* - data3 = max value - */ + /* - data4 = step value - */ + /* - min > max = sub, min < max = sum - */ + /* - hitag: 0 = force OFF if goal value was reached for all objects - */ + /* - hitag: 2 = force swap min and max if goal value was reached - */ + /* - hitag: 3 = force reset counter - */ + long data = getDataFieldOfObject(type, nDest, pXSource->data1); + if (data == -65535) return; + + if (pXSource->data2 < pXSource->data3) { + + if (data < pXSource->data2) data = pXSource->data2; + if (data > pXSource->data3) data = pXSource->data3; + + if ((data += pXSource->data4) >= pXSource->data3) { + + switch (pSource->hitag) { + case kModernTypeFlag0: + case kModernTypeFlag1: + if (data > pXSource->data3) data = pXSource->data3; + break; + case kModernTypeFlag2: { + if (data > pXSource->data3) data = pXSource->data3; + if (!goalValueIsReached(pXSource)) break; + short tmp = pXSource->data3; + pXSource->data3 = pXSource->data2; + pXSource->data2 = tmp; + } + break; + case kModernTypeFlag3: + if (data > pXSource->data3) data = pXSource->data2; + break; + } + } + + } else if (pXSource->data2 > pXSource->data3) { + + if (data > pXSource->data2) data = pXSource->data2; + if (data < pXSource->data3) data = pXSource->data3; + + if ((data -= pXSource->data4) <= pXSource->data3) { + switch (pSource->hitag) { + case kModernTypeFlag0: + case kModernTypeFlag1: + if (data < pXSource->data3) data = pXSource->data3; + break; + case kModernTypeFlag2: { + if (data < pXSource->data3) data = pXSource->data3; + if (!goalValueIsReached(pXSource)) break; + short tmp = pXSource->data3; + pXSource->data3 = pXSource->data2; + pXSource->data2 = tmp; + } + break; + case kModernTypeFlag3: + if (data < pXSource->data3) data = pXSource->data2; + break; + } + } + } + + setDataValueOfObject(type, nDest, pXSource->data1, data); + + return; + } else if (pSource->type == kGDXObjDataChanger) { /* - Data field changer via TX - */ @@ -2598,87 +2949,74 @@ void pastePropertiesInObj(int type, int nDest, EVENT event) { /* - data3 = sprite data3 - */ /* - data4 = sprite data4 - */ + /* - hitag: 1 = treat "ignore value" as actual value - */ + switch (type) { - // for sectors case 6: - { - XSECTOR* pXSector = &xsector[sector[nDest].extra]; - - if (valueIsBetween(pXSource->data1, -1, 32767)) - pXSector->data = pXSource->data1; - + if ((pSource->hitag & kModernTypeFlag1) || (pXSource->data1 != -1 && pXSource->data1 != 32767)) + setDataValueOfObject(type, nDest, 1, pXSource->data1); break; - } - // for sprites + case 3: - { - XSPRITE* pXSprite = &xsprite[sprite[nDest].extra]; + if ((pSource->hitag & kModernTypeFlag1) || (pXSource->data1 != -1 && pXSource->data1 != 32767)) + setDataValueOfObject(type, nDest, 1, pXSource->data1); - if (valueIsBetween(pXSource->data1, -1, 32767)) - pXSprite->data1 = pXSource->data1; + if ((pSource->hitag & kModernTypeFlag1) || (pXSource->data2 != -1 && pXSource->data2 != 32767)) + setDataValueOfObject(type, nDest, 2, pXSource->data2); - if (valueIsBetween(pXSource->data2, -1, 32767)) - pXSprite->data2 = pXSource->data2; - - if (valueIsBetween(pXSource->data3, -1, 32767)) - pXSprite->data3 = pXSource->data3; - - if (valueIsBetween(pXSource->data4, -1, 65535)) - pXSprite->data4 = pXSource->data4; + if ((pSource->hitag & kModernTypeFlag1) || (pXSource->data3 != -1 && pXSource->data3 != 32767)) + setDataValueOfObject(type, nDest, 3, pXSource->data3); + if ((pSource->hitag & kModernTypeFlag1) || (pXSource->data4 != -1 && pXSource->data1 != 65535)) + setDataValueOfObject(type, nDest, 4, pXSource->data4); break; - } - // for walls + case 0: - { - XWALL* pXWall = &xwall[wall[nDest].extra]; - - if (valueIsBetween(pXSource->data1, -1, 32767)) - pXWall->data = pXSource->data1; - + if ((pSource->hitag & kModernTypeFlag1) || (pXSource->data1 != -1 && pXSource->data1 != 32767)) + setDataValueOfObject(type, nDest, 1, pXSource->data1); break; - } } } else if (pSource->type == kGDXSectorFXChanger) { /* - FX Wave changer for sector via TX - */ - /* - data1 = Wave - */ - /* - data2 = Amplitude - */ - /* - data3 = Freq - */ - /* - data4 = Phase - */ + /* - data1 = Wave - */ + /* - data2 = Amplitude - */ + /* - data3 = Freq - */ + /* - data4 = Phase - */ - if (type == 6) { - XSECTOR* pXSector = &xsector[sector[nDest].extra]; - if (valueIsBetween(pXSource->data1, -1, 32767)) - pXSector->wave = pXSource->data1; + if (type != 6) return; + XSECTOR* pXSector = &xsector[sector[nDest].extra]; - if (pXSource->data2 >= 0) { + if (valueIsBetween(pXSource->data1, -1, 32767)) + pXSector->wave = (pXSource->data1 > 11) ? 11 : pXSource->data1; - if (pXSource->data2 > 127) pXSector->amplitude = 127; - else pXSector->amplitude = pXSource->data2; + int oldAmplitude = pXSector->amplitude; + if (pXSource->data2 >= 0) pXSector->amplitude = (pXSource->data2 > 127) ? 127 : pXSource->data2; + else if (pXSource->data2 < -1) pXSector->amplitude = (pXSource->data2 < -127) ? -127 : pXSource->data2; - } - else if (pXSource->data2 < -1) { + if (valueIsBetween(pXSource->data3, -1, 32767)) + pXSector->freq = (pXSource->data3 > 255) ? 255 : pXSource->data3; - if (pXSource->data2 < -127) pXSector->amplitude = -127; - else pXSector->amplitude = pXSource->data2; + if (valueIsBetween(pXSource->data4, -1, 65535)) + pXSector->phase = (pXSource->data4 > 255) ? 255 : pXSource->data4; + // force shadeAlways + if (pSource->hitag & kModernTypeFlag1) + pXSector->shadeAlways = true; + + // add to shadeList if amplitude was set to 0 previously + if (oldAmplitude == 0 && pXSector->amplitude != 0 && shadeCount < kMaxXSectors) { + + bool found = false; + for (int i = 0; i < shadeCount; i++) { + if (shadeList[i] != sector[nDest].extra) continue; + found = true; + break; } - if (valueIsBetween(pXSource->data3, -1, 32767)) { - if (pXSource->data3 > 255) pXSector->freq = 255; - else pXSector->freq = pXSource->data3; - } - - if (valueIsBetween(pXSource->data4, -1, 65535)) { - if (pXSource->data4 > 255) pXSector->phase = 255; - else pXSector->phase = (short)pXSource->data4; - } - - if ((pSource->hitag & kHitagExtBit) != 0) - pXSector->shadeAlways = true; - + if (!found) + shadeList[shadeCount++] = sector[nDest].extra; } } else if (pSource->type == kGDXDudeTargetChanger) { @@ -2735,12 +3073,12 @@ void pastePropertiesInObj(int type, int nDest, EVENT event) { if (pXSource->data4 == 3) { aiSetTarget(pXSprite, pSprite->x, pSprite->y, pSprite->z); aiSetGenIdleState(pSprite, pXSprite); - if (pSprite->lotag == kGDXDudeUniversalCultist) + if (pSprite->lotag == kCustomDude) removeLeech(leechIsDropped(pSprite)); } else if (pXSource->data4 == 4) { aiSetTarget(pXSprite, pPlayer->x, pPlayer->y, pPlayer->z); - if (pSprite->lotag == kGDXDudeUniversalCultist) + if (pSprite->lotag == kCustomDude) removeLeech(leechIsDropped(pSprite)); } } @@ -2884,7 +3222,7 @@ void pastePropertiesInObj(int type, int nDest, EVENT event) { // if Target Changer have data1 = 666, everyone can be target, except AI team mates. else if (pXSource->data1 != 666 && pXSource->data1 != pXTarget->data1) continue; // don't attack immortal, burning dudes and mates - if (IsBurningDude(pTarget) || !IsKillableDude(pTarget, true) || (pXSource->data2 == 1 && isMateOf(pXSprite, pXTarget))) + if (IsBurningDude(pTarget) || !IsKillableDude(pTarget) || (pXSource->data2 == 1 && isMateOf(pXSprite, pXTarget))) continue; if (pXSource->data2 == 0 || (pXSource->data2 == 1 && !isMatesHaveSameTarget(pXSprite, pTarget, matesPerEnemy))) { @@ -2968,43 +3306,25 @@ void pastePropertiesInObj(int type, int nDest, EVENT event) { sector[nDest].ceilingxpanning = pXSource->data3; if (valueIsBetween(pXSource->data4, -1, 65535)) - sector[nDest].ceilingypanning = (short)pXSource->data4; + sector[nDest].ceilingypanning = pXSource->data4; break; // for sprites case 3: - - if (valueIsBetween(pXSource->data1, -1, 32767) && - valueIsBetween(pXSource->data2, -1, 32767) && - pXSource->data1 < 4 && pXSource->data2 < 4) - { - - sprite[nDest].xrepeat = 4; - sprite[nDest].yrepeat = 4; - sprite[nDest].cstat |= CSTAT_SPRITE_INVISIBLE; - + if (valueIsBetween(pXSource->data1, -1, 32767)) { + if (pXSource->data1 < 1) sprite[nDest].xrepeat = 0; + else sprite[nDest].xrepeat = pXSource->data1; } - else { - if (valueIsBetween(pXSource->data1, -1, 32767)) { - if (pXSource->data1 < 4) - sprite[nDest].xrepeat = 4; - else - sprite[nDest].xrepeat = pXSource->data1; - } - - if (valueIsBetween(pXSource->data2, -1, 32767)) { - if (pXSource->data2 < 4) - sprite[nDest].yrepeat = 4; - else - sprite[nDest].yrepeat = pXSource->data2; - } + if (valueIsBetween(pXSource->data2, -1, 32767)) { + if (pXSource->data2 < 1) sprite[nDest].yrepeat = 0; + else sprite[nDest].yrepeat = pXSource->data2; } if (valueIsBetween(pXSource->data3, -1, 32767)) sprite[nDest].xoffset = pXSource->data3; if (valueIsBetween(pXSource->data4, -1, 65535)) - sprite[nDest].yoffset = (short)pXSource->data4; + sprite[nDest].yoffset = pXSource->data4; break; // for walls @@ -3016,10 +3336,10 @@ void pastePropertiesInObj(int type, int nDest, EVENT event) { wall[nDest].yrepeat = pXSource->data2; if (valueIsBetween(pXSource->data3, -1, 32767)) - wall[nDest].xpanning = (short)pXSource->data3; + wall[nDest].xpanning = pXSource->data3; if (valueIsBetween(pXSource->data4, -1, 65535)) - wall[nDest].ypanning = (short)pXSource->data4; + wall[nDest].ypanning = pXSource->data4; break; } @@ -3028,6 +3348,7 @@ void pastePropertiesInObj(int type, int nDest, EVENT event) { /* - picnum changer can change picnum of sprite/wall/sector via TX ID - */ /* - data1 = sprite pic / wall pic / sector floor pic - */ + /* - data2 = sprite shade / wall overpic / sector ceil pic - */ /* - data3 = sprite pal / wall pal / sector floor pic - */ switch (type) { @@ -3043,14 +3364,14 @@ void pastePropertiesInObj(int type, int nDest, EVENT event) { XSECTOR *pXSector = &xsector[sector[nDest].extra]; if (valueIsBetween(pXSource->data3, -1, 32767)) { sector[nDest].floorpal = pXSource->data3; - if ((pSource->hitag & kHitagExtBit) != 0) + if (pSource->hitag & kModernTypeFlag1) pXSector->floorpal = pXSource->data3; } if (valueIsBetween(pXSource->data4, -1, 65535)) { - sector[nDest].ceilingpal = (short)pXSource->data4; - if ((pSource->hitag & kHitagExtBit) != 0) - pXSector->ceilpal = (short)pXSource->data4; + sector[nDest].ceilingpal = pXSource->data4; + if (pSource->hitag & kModernTypeFlag1) + pXSector->ceilpal = pXSource->data4; } break; } @@ -3059,6 +3380,9 @@ void pastePropertiesInObj(int type, int nDest, EVENT event) { if (valueIsBetween(pXSource->data1, -1, 32767)) sprite[nDest].picnum = pXSource->data1; + if (pXSource->data2 >= 0) sprite[nDest].shade = (pXSource->data2 > 127) ? 127 : pXSource->data2; + else if (pXSource->data2 < -1) sprite[nDest].shade = (pXSource->data2 < -127) ? -127 : pXSource->data2; + if (valueIsBetween(pXSource->data3, -1, 32767)) sprite[nDest].pal = pXSource->data3; break; @@ -3082,48 +3406,20 @@ void pastePropertiesInObj(int type, int nDest, EVENT event) { /* - data2 = sector visibility - */ /* - data3 = sector ceiling cstat / sprite / wall hitag - */ /* - data4 = sector floor / sprite / wall cstat - */ - + int old = -1; switch (type) { // for sectors case 6: { XSECTOR* pXSector = &xsector[sector[nDest].extra]; - switch (pXSource->data1) { - case 0: - pXSector->Underwater = false; - break; - case 1: - pXSector->Underwater = true; - break; - case 2: - pXSector->Depth = 0; - break; - case 3: - pXSector->Depth = 1; - break; - case 4: - pXSector->Depth = 2; - break; - case 5: - pXSector->Depth = 3; - break; - case 6: - pXSector->Depth = 4; - break; - case 7: - pXSector->Depth = 5; - break; - case 8: - pXSector->Depth = 6; - break; - case 9: - pXSector->Depth = 7; - break; - } + if (pXSource->data1 == 0) pXSector->Underwater = false; + else if (pXSource->data1 == 1) pXSector->Underwater = true; + else if (pXSource->data1 > 9) pXSector->Depth = 7; + else if (pXSource->data1 > 1) pXSector->Depth = pXSource->data1 - 2; if (valueIsBetween(pXSource->data2, -1, 32767)) { - if (pXSource->data2 > 255) sector[nDest].visibility = 255; + if (pXSource->data2 > 234) sector[nDest].visibility = 234; else sector[nDest].visibility = pXSource->data2; } @@ -3135,26 +3431,188 @@ void pastePropertiesInObj(int type, int nDest, EVENT event) { break; } // for sprites - case 3: - if (valueIsBetween(pXSource->data3, -1, 32767)) - sprite[nDest].hitag = pXSource->data3; + case 3: { + + spritetype* pSprite = &sprite[nDest]; bool thing2debris = false; + XSPRITE* pXSprite = &xsprite[pSprite->extra]; + + if (valueIsBetween(pXSource->data3, -1, 32767)) { + old = pSprite->hitag; pSprite->hitag = pXSource->data3; // set new hitag + + // and handle exceptions + if ((old & kHitagFree) && !(pSprite->hitag & kHitagFree)) pSprite->hitag |= kHitagFree; + if ((old & kHitagRespawn) && !(pSprite->hitag & kHitagRespawn)) pSprite->hitag |= kHitagRespawn; + + // prepare things for different (debris) physics. + if (pSprite->statnum == 4 && debrisGetFreeIndex() >= 0) thing2debris = true; + + } + + if ((pXSource->data2 >= 0 && pXSource->data3 <= 33) || thing2debris) { + switch (pSprite->statnum) { + case 6: // dudes already treating in game + case kStatFree: + case kStatMarker: + case 16: // path marker + break; + default: + // store physics attributes in xsprite to avoid setting hitag for modern types! + int flags = (pXSprite->physAttr != 0) ? pXSprite->physAttr : 0; + + if (thing2debris) { + + // converting thing to debris + if ((pSprite->hitag & kPhysMove) != 0) flags |= kPhysMove; + else flags &= ~kPhysMove; + + if ((pSprite->hitag & kPhysGravity) != 0) flags |= (kPhysGravity | kPhysFalling); + else flags &= ~(kPhysGravity | kPhysFalling); + + pSprite->hitag &= ~(kPhysMove | kPhysGravity | kPhysFalling); + xvel[nDest] = yvel[nDest] = zvel[nDest] = 0; pXSprite->restState = pXSprite->state; + + } else { + + // first digit of data2: set main physics attributes first + switch (pXSource->data2) { + case 0: + flags &= ~kPhysMove; + flags &= ~(kPhysGravity | kPhysFalling); + break; + + case 1: case 10: case 11: case 12: case 13: + flags |= kPhysMove; + flags &= ~(kPhysGravity | kPhysFalling); + break; + + case 2: case 20: case 21: case 22: case 23: + flags &= ~kPhysMove; + flags |= (kPhysGravity | kPhysFalling); + break; + + case 3: case 30: case 31: case 32: case 33: + flags |= kPhysMove; + flags |= (kPhysGravity | kPhysFalling); + break; + } + + // second digit of data2: then set physics flags + switch (pXSource->data2) { + case 0: case 1: case 2: case 3: + case 10: case 20: case 30: + flags &= ~kPhysDebrisVector; + flags &= ~kPhysDebrisExplode; + break; + + case 11: case 21: case 31: + flags |= kPhysDebrisVector; + flags &= ~kPhysDebrisExplode; + break; + + case 12: case 22: case 32: + flags &= ~kPhysDebrisVector; + flags |= kPhysDebrisExplode; + break; + + case 13: case 23: case 33: + flags |= kPhysDebrisVector; + flags |= kPhysDebrisExplode; + break; + } + + } + + int nIndex = isDebris(nDest); // check if there is no sprite in list + + // adding physics sprite in list + if ((flags & kPhysGravity) != 0 || (flags & kPhysMove) != 0) { + if (nIndex != -1) pXSprite->physAttr = flags; // just update physics attributes + else if ((nIndex = debrisGetFreeIndex()) < 0) + ;// showWarning("Max (%d) Physics affected sprites reached!", kMaxSuperXSprites); + else { + + pXSprite->physAttr = flags; // update physics attributes + + // allow things to became debris, so they use different physics... + if (pSprite->statnum == 4) changespritestat(nDest, 0); + //actPostSprite(nDest, 0); // !!!! not working here for some reason + + gPhysSpritesList[nIndex] = nDest; + if (nIndex >= gPhysSpritesCount) gPhysSpritesCount++; + getSpriteMassBySize(pSprite); // create physics cache + + } + // removing physics from sprite in list (don't remove sprite from list) + } else if (nIndex != -1) { + pXSprite->physAttr = flags; + xvel[nDest] = yvel[nDest] = zvel[nDest] = 0; + if (pSprite->lotag >= kThingBase && pSprite->lotag < kThingMax) + changespritestat(nDest, 4); // if it was a thing - restore statnum + } + + break; + } + } if (valueIsBetween(pXSource->data4, -1, 65535)) { - pXSource->data4 |= CSTAT_SPRITE_YCENTER; - sprite[nDest].cstat = pXSource->data4; - } - break; - // for walls - case 0: - if (valueIsBetween(pXSource->data3, -1, 32767)) - wall[nDest].hitag = pXSource->data3; - if (valueIsBetween(pXSource->data4, -1, 65535)) - wall[nDest].cstat = pXSource->data4; + old = pSprite->cstat; + pSprite->cstat = pXSource->data4; // set new cstat + + // and handle exceptions + if ((old & 0x1000) && !(pSprite->cstat & 0x1000)) pSprite->cstat |= 0x1000; //kSpritePushable + if ((old & 0x80) && !(pSprite->cstat & 0x80)) pSprite->cstat |= 0x80; // kSpriteOriginAlign + + if (old & 0x6000) { + + if (!(pSprite->cstat & 0x6000)) + pSprite->cstat |= 0x6000; // kSpriteMoveMask + + if ((old & 0x0) && !(pSprite->cstat & 0x0)) pSprite->cstat |= 0x0; // kSpriteMoveNone + else if ((old & 0x2000) && !(pSprite->cstat & 0x2000)) pSprite->cstat |= 0x2000; // kSpriteMoveForward, kSpriteMoveFloor + else if ((old & 0x4000) && !(pSprite->cstat & 0x4000)) pSprite->cstat |= 0x4000; // kSpriteMoveReverse, kSpriteMoveCeiling + + } + + } + + } + break; + // for walls + case 0: { + + walltype* pWall = &wall[nDest]; + if (valueIsBetween(pXSource->data3, -1, 32767)) + pWall->hitag = pXSource->data3; + + if (valueIsBetween(pXSource->data4, -1, 65535)) { + old = pWall->cstat; + pWall->cstat = pXSource->data4; // set new cstat + + // and hanlde exceptions + if ((old & 0x2) && !(pWall->cstat & 0x2)) pWall->cstat |= 0x2; // kWallBottomSwap + if ((old & 0x4) && !(pWall->cstat & 0x4)) pWall->cstat |= 0x4; // kWallBottomOrg, kWallOutsideOrg + if ((old & 0x20) && !(pWall->cstat & 0x20)) pWall->cstat |= 0x20; // kWallOneWay + + if (old & 0xc000) { + + if (!(pWall->cstat & 0xc000)) + pWall->cstat |= 0xc000; // kWallMoveMask + + if ((old & 0x0) && !(pWall->cstat & 0x0)) pWall->cstat |= 0x0; // kWallMoveNone + else if ((old & 0x4000) && !(pWall->cstat & 0x4000)) pWall->cstat |= 0x4000; // kWallMoveForward + else if ((old & 0x8000) && !(pWall->cstat & 0x8000)) pWall->cstat |= 0x8000; // kWallMoveBackward + + } + + } + + } break; } } } + // By NoOne: the following functions required for kGDXDudeTargetChanger //--------------------------------------- spritetype* getTargetInRange(spritetype* pSprite, int minDist, int maxDist, short data, short teamMode) { @@ -3168,7 +3626,7 @@ spritetype* getTargetInRange(spritetype* pSprite, int minDist, int maxDist, shor if (dist < minDist || dist > maxDist) continue; else if (pXSprite->target == pTarget->xvel) return pTarget; else if (!IsDudeSprite(pTarget) || pTarget->xvel == pSprite->xvel || IsPlayerSprite(pTarget)) continue; - else if (IsBurningDude(pTarget) || !IsKillableDude(pTarget, true) || pTarget->owner == pSprite->xvel) continue; + else if (IsBurningDude(pTarget) || !IsKillableDude(pTarget) || pTarget->owner == pSprite->xvel) continue; else if ((teamMode == 1 && isMateOf(pXSprite, pXTarget)) || isMatesHaveSameTarget(pXSprite,pTarget,1)) continue; else if (data == 666 || pXTarget->data1 == data) { @@ -3320,7 +3778,12 @@ int getDataFieldOfObject(int objType, int objIndex, int dataIndex) { case 2: return xsprite[sprite[objIndex].extra].data2; case 3: - return xsprite[sprite[objIndex].extra].data3; + switch (sprite[objIndex].type) { + case kCustomDude: + return xsprite[sprite[objIndex].extra].sysData1; + default: + return xsprite[sprite[objIndex].extra].data3; + } case 4: return xsprite[sprite[objIndex].extra].data4; default: @@ -3337,29 +3800,44 @@ int getDataFieldOfObject(int objType, int objIndex, int dataIndex) { bool setDataValueOfObject(int objType, int objIndex, int dataIndex, int value) { switch (objType) { - case 3: - switch (dataIndex) { - case 1: - xsprite[sprite[objIndex].extra].data1 = value; - return true; - case 2: - xsprite[sprite[objIndex].extra].data2 = value; - return true; case 3: - xsprite[sprite[objIndex].extra].data3 = value; + switch (dataIndex) { + case 1: + xsprite[sprite[objIndex].extra].data1 = value; + switch (sprite[objIndex].type) { + case kSwitchCombo: + if (xsprite[sprite[objIndex].extra].data1 == xsprite[sprite[objIndex].extra].data2) + SetSpriteState(objIndex, &xsprite[sprite[objIndex].extra], 1); + else + SetSpriteState(objIndex, &xsprite[sprite[objIndex].extra], 0); + break; + } + return true; + case 2: + xsprite[sprite[objIndex].extra].data2 = value; + return true; + case 3: + switch (sprite[objIndex].type) { + case kCustomDude: + xsprite[sprite[objIndex].extra].sysData1 = value; + break; + default: + xsprite[sprite[objIndex].extra].data3 = value; + break; + } + return true; + case 4: + xsprite[sprite[objIndex].extra].data4 = value; + return true; + default: + return false; + } + case 0: + xsector[sector[objIndex].extra].data = value; return true; - case 4: - xsprite[sprite[objIndex].extra].data4 = value; + case 6: + xwall[wall[objIndex].extra].data = value; return true; - default: - return false; - } - case 0: - xsector[sector[objIndex].extra].data = value; - return true; - case 6: - xwall[wall[objIndex].extra].data = value; - return true; default: return false; } @@ -3368,7 +3846,7 @@ bool setDataValueOfObject(int objType, int objIndex, int dataIndex, int value) { // by NoOne: this function checks if all TX objects have the same value bool goalValueIsReached(XSPRITE* pXSprite) { for (int i = bucketHead[pXSprite->txID]; i < bucketHead[pXSprite->txID + 1]; i++) { - if (getDataFieldOfObject(rxBucket[i].type, rxBucket[i].index, pXSprite->data1) != pXSprite->data4) + if (getDataFieldOfObject(rxBucket[i].type, rxBucket[i].index, pXSprite->data1) != pXSprite->data3) return false; } return true; @@ -3444,30 +3922,22 @@ bool IsBurningDude(spritetype* pSprite) { case 242: // fat zombie burning case 252: // tiny caleb burning case 253: // beast burning - case kGDXGenDudeBurning: + case kCustomDudeBurning: return true; } return false; } -bool IsKillableDude(spritetype* pSprite, bool locked) { - if (!IsDudeSprite(pSprite)) return false; - DUDEINFO* pDudeInfo = &dudeInfo[pSprite->lotag - kDudeBase]; - - // Optionally check if dude is locked - if (locked && xsprite[pSprite->extra].locked == 1) +bool IsKillableDude(spritetype* pSprite) { + switch (pSprite->type) { + case 208: // flesh statue + case 209: // stone statue return false; - - - // Make sure damage shift is greater than 0; - int a = 0; - for (int i = 0; i <= 6; i++) { - a += pDudeInfo->startDamage[i]; + default: + if (!IsDudeSprite(pSprite) || xsprite[pSprite->extra].locked == 1) return false; + return true; } - - if (a == 0) return false; - return true; } bool isAnnoyingUnit(spritetype* pDude) { @@ -3525,7 +3995,7 @@ bool isMeleeUnit(spritetype* pDude) { case 250: // tiny caleb case 251: // beast return true; - case kGDXDudeUniversalCultist: + case kCustomDude: return (pDude->extra >= 0 && dudeIsMelee(&xsprite[pDude->extra])); default: return false; @@ -3786,9 +4256,10 @@ void trInit(void) case 23: pXSprite->triggerOnce = 1; break; - case kGDXSequentialTX: - break; + case 40: // Random weapon + case 80: // Random ammo case kGDXSeqSpawner: + case kGDXObjDataAccumulator: case kGDXDudeTargetChanger: case kGDXEffectSpawner: case kGDXWindGenerator: @@ -3847,9 +4318,15 @@ void InitGenerator(int nSprite) int nXSprite = pSprite->extra; dassert(nXSprite > 0); XSPRITE *pXSprite = &xsprite[nXSprite]; - switch (sprite[nSprite].type) - { + switch (sprite[nSprite].type) { // By NoOne: intialize GDX generators + case 40: // Random weapon + case 80: // Random ammo + pSprite->cstat &= ~CSTAT_SPRITE_BLOCK; + pSprite->cstat |= CSTAT_SPRITE_INVISIBLE; + if (pXSprite->state != pXSprite->restState) + evPost(nSprite, 3, (120 * pXSprite->busyTime) / 10, COMMAND_ID_21); + return; case kGDXDudeTargetChanger: pSprite->cstat &= ~CSTAT_SPRITE_BLOCK; pSprite->cstat |= CSTAT_SPRITE_INVISIBLE; @@ -3857,14 +4334,22 @@ void InitGenerator(int nSprite) if (pXSprite->state != pXSprite->restState) evPost(nSprite, 3, 0, COMMAND_ID_21); return; - case kGDXObjDataAccumulator: - case kGDXSeqSpawner: case kGDXEffectSpawner: + case kGDXSeqSpawner: + if (pXSprite->state != pXSprite->restState) + evPost(nSprite, 3, 0, COMMAND_ID_21); + return; + case kGDXObjDataAccumulator: pSprite->cstat &= ~CSTAT_SPRITE_BLOCK; pSprite->cstat |= CSTAT_SPRITE_INVISIBLE; if (pXSprite->state != pXSprite->restState) evPost(nSprite, 3, 0, COMMAND_ID_21); return; + case kGDXWindGenerator: + pSprite->cstat &= ~CSTAT_SPRITE_BLOCK; + if (pXSprite->state != pXSprite->restState) + evPost(nSprite, 3, 0, COMMAND_ID_21); + return; case 700: pSprite->cstat &= ~CSTAT_SPRITE_BLOCK; pSprite->cstat |= CSTAT_SPRITE_INVISIBLE; @@ -3883,70 +4368,93 @@ void ActivateGenerator(int nSprite) dassert(nXSprite > 0); XSPRITE *pXSprite = &xsprite[nXSprite]; switch (pSprite->type) { - case 701: - { - int top, bottom; - GetSpriteExtents(pSprite, &top, &bottom); - actSpawnThing(pSprite->sectnum, pSprite->x, pSprite->y, bottom, 423); - break; - } - case 702: - { - int top, bottom; - GetSpriteExtents(pSprite, &top, &bottom); - actSpawnThing(pSprite->sectnum, pSprite->x, pSprite->y, bottom, 424); - break; - } - case 708: - { - // By NoOne: allow custom pitch for sounds in SFX gen. - int pitch = pXSprite->data4 << 1; if (pitch < 2000) pitch = 0; - sfxPlay3DSoundCP(pSprite, pXSprite->data2, -1, 0, pitch); - break; - } - case 703: - switch (pXSprite->data2) + case 40: // Random weapon + case 80: { // Random ammo + // let's first search for previously dropped items and remove it + if (pXSprite->dropMsg > 0) { + for (short nItem = headspritestat[3]; nItem >= 0; nItem = nextspritestat[nItem]) { + spritetype* pItem = &sprite[nItem]; + if (pItem->lotag == pXSprite->dropMsg && pItem->x == pSprite->x && pItem->y == pSprite->y && pItem->z == pSprite->z) { + gFX.fxSpawn((FX_ID)29, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0); + deletesprite(nItem); + break; + } + } + } + + // then drop item + spritetype* pDrop = DropRandomPickupObject(pSprite, pXSprite->dropMsg); + + // check if generator affected by physics + if (pDrop != NULL && isDebris(pSprite->xvel) != -1 && (pDrop->extra >= 0 || dbInsertXSprite(pDrop->xvel) > 0)) { + int nIndex = debrisGetFreeIndex(); + if (nIndex >= 0) { + xsprite[pDrop->extra].physAttr |= kPhysMove | kPhysGravity | kPhysFalling; // must fall always + pSprite->cstat &= ~CSTAT_SPRITE_BLOCK; + + gPhysSpritesList[nIndex] = pDrop->xvel; + if (nIndex >= gPhysSpritesCount) gPhysSpritesCount++; + getSpriteMassBySize(pDrop); // create mass cache + } + } + } + break; + case 701: { - case 0: - FireballTrapSeqCallback(3, nXSprite); - break; - case 1: - seqSpawn(35, 3, nXSprite, nFireballTrapClient); - break; - case 2: - seqSpawn(36, 3, nXSprite, nFireballTrapClient); + int top, bottom; + GetSpriteExtents(pSprite, &top, &bottom); + actSpawnThing(pSprite->sectnum, pSprite->x, pSprite->y, bottom, 423); break; } - break; - // By NoOne: EctoSkull gen can now fire any missile - case 704: - switch (pXSprite->data2) + case 702: { - case 0: + int top, bottom; + GetSpriteExtents(pSprite, &top, &bottom); + actSpawnThing(pSprite->sectnum, pSprite->x, pSprite->y, bottom, 424); + break; + } + case 708: + { + // By NoOne: allow custom pitch and volume for sounds in SFX gen. + if (VanillaMode()) sfxPlay3DSound(pSprite, pXSprite->data2, -1, 0); + else { + int pitch = pXSprite->data4 << 1; if (pitch < 2000) pitch = 0; + sfxPlay3DSoundCP(pSprite, pXSprite->data2, -1, 0, pitch, pXSprite->data3); + } + break; + } + case 703: + switch (pXSprite->data2) + { + case 0: + FireballTrapSeqCallback(3, nXSprite); + break; + case 1: + seqSpawn(35, 3, nXSprite, nFireballTrapClient); + break; + case 2: + seqSpawn(36, 3, nXSprite, nFireballTrapClient); + break; + } + break; + // By NoOne: EctoSkull gen can now fire any missile + case 704: UniMissileTrapSeqCallback(3, nXSprite); break; - case 1: - seqSpawn(35, 3, nXSprite, nUniMissileTrapClient); - break; - case 2: - seqSpawn(36, 3, nXSprite, nUniMissileTrapClient); + case 706: + { + int top, bottom; + GetSpriteExtents(pSprite, &top, &bottom); + gFX.fxSpawn(FX_23, pSprite->sectnum, pSprite->x, pSprite->y, top, 0); + break; + } + case 707: + { + int top, bottom; + GetSpriteExtents(pSprite, &top, &bottom); + gFX.fxSpawn(FX_26, pSprite->sectnum, pSprite->x, pSprite->y, top, 0); break; } - break; - case 706: - { - int top, bottom; - GetSpriteExtents(pSprite, &top, &bottom); - gFX.fxSpawn(FX_23, pSprite->sectnum, pSprite->x, pSprite->y, top, 0); - break; - } - case 707: - { - int top, bottom; - GetSpriteExtents(pSprite, &top, &bottom); - gFX.fxSpawn(FX_26, pSprite->sectnum, pSprite->x, pSprite->y, top, 0); - break; - } } } @@ -3961,23 +4469,58 @@ void FireballTrapSeqCallback(int, int nXSprite) actFireMissile(pSprite, 0, 0, Cos(pSprite->ang)>>16, Sin(pSprite->ang)>>16, 0, 305); } -// By NoOne: Callback for trap that can fire any missile specified in data3 +// By NoOne: Callback for trap that can fire any missile specified in data1 void UniMissileTrapSeqCallback(int, int nXSprite) { - XSPRITE *pXSprite = &xsprite[nXSprite]; - int nSprite = pXSprite->reference; - spritetype *pSprite = &sprite[nSprite]; - - int nMissile = 307; - if (pXSprite->data3 >= kMissileBase && pXSprite->data3 < kMissileMax) - nMissile = pXSprite->data3; - else + + XSPRITE* pXSprite = &xsprite[nXSprite]; int dx = 0, dy = 0, dz = 0; + spritetype* pSprite = &sprite[pXSprite->reference]; + + if (pXSprite->data1 < kMissileBase || pXSprite->data1 >= kMissileMax) return; - if (pSprite->cstat&32) - actFireMissile(pSprite, 0, 0, 0, 0, (pSprite->cstat&8) ? 0x4000 : -0x4000, nMissile); - else - actFireMissile(pSprite, 0, 0, Cos(pSprite->ang)>>16, Sin(pSprite->ang)>>16, 0, nMissile); + if (pSprite->cstat & 32) { + if (pSprite->cstat & 8) dz = 0x4000; + else dz = -0x4000; + } else { + dx = Cos(pSprite->ang) >> 16; + dy = Sin(pSprite->ang) >> 16; + dz = pXSprite->data3 << 6; // add slope controlling + if (dz > 0x10000) dz = 0x10000; + else if (dz < -0x10000) dz = -0x10000; + } + + spritetype* pMissile = NULL; + pMissile = actFireMissile(pSprite, 0, 0, dx, dy, dz, pXSprite->data1); + if (pMissile != NULL) { + + // inherit some properties of the generator + if (pSprite->hitag & kModernTypeFlag1) { + + pMissile->xrepeat = pSprite->xrepeat; + pMissile->yrepeat = pSprite->yrepeat; + + pMissile->pal = pSprite->pal; + pMissile->shade = pSprite->shade; + + } + + // add velocity controlling + if (pXSprite->data2 > 0) { + + long velocity = pXSprite->data2 << 12; + xvel[pMissile->xvel] = mulscale(velocity, dx, 14); + yvel[pMissile->xvel] = mulscale(velocity, dy, 14); + zvel[pMissile->xvel] = mulscale(velocity, dz, 14); + + } + + // add bursting for missiles + if (pMissile->type != 303 && pXSprite->data4 > 0) + evPost(pMissile->xvel, 3, (pXSprite->data4 > 500) ? 500 : pXSprite->data4 - 1, CALLBACK_ID_22); + + } + } void MGunFireSeqCallback(int, int nXSprite) diff --git a/source/blood/src/triggers.h b/source/blood/src/triggers.h index 498f42659..1134eb63e 100644 --- a/source/blood/src/triggers.h +++ b/source/blood/src/triggers.h @@ -43,7 +43,6 @@ void trTextOver(int nId); // By NoOne: functions required for new features // ------------------------------------------------------- void pastePropertiesInObj(int type, int nDest, EVENT event); -void trDamageSprite(int type, int nDest, EVENT event); spritetype* getTargetInRange(spritetype* pSprite, int minDist, int maxDist, short data, short teamMode); bool isMateOf(XSPRITE* pXDude, XSPRITE* pXSprite); spritetype* targetIsPlayer(XSPRITE* pXSprite); @@ -56,7 +55,7 @@ void disturbDudesInSight(spritetype* pSprite, int max); int getTargetDist(spritetype* pSprite, DUDEINFO* pDudeInfo, spritetype* pTarget); int getFineTargetDist(spritetype* pSprite, spritetype* pTarget); bool IsBurningDude(spritetype* pSprite); -bool IsKillableDude(spritetype* pSprite, bool locked); +bool IsKillableDude(spritetype* pSprite); bool isAnnoyingUnit(spritetype* pDude); bool unitCanFly(spritetype* pDude); bool isMeleeUnit(spritetype* pDude); @@ -69,5 +68,8 @@ bool getDudesForTargetChg(XSPRITE* pXSprite); void stopWindOnSectors(XSPRITE* pXSource); void useSectorWindGen(XSPRITE* pXSource, sectortype* pSector); void useEffectGen(XSPRITE* pXSource, spritetype* pSprite); -void useSeqSpawnerGen(XSPRITE* pXSource, spritetype* pSprite); +void useSeqSpawnerGen(XSPRITE* pXSource, int objType, int index); +void useSpriteDamager(XSPRITE* pXSource, spritetype* pSprite); +void useTeleportTarget(XSPRITE* pXSource, spritetype* pSprite); +void TeleFrag(int nKiller, int nSector); // ------------------------------------------------------- \ No newline at end of file diff --git a/source/blood/src/view.cpp b/source/blood/src/view.cpp index 845f8dc52..e7e8a2512 100644 --- a/source/blood/src/view.cpp +++ b/source/blood/src/view.cpp @@ -1023,10 +1023,10 @@ void viewTileSprite(int nTile, int nShade, int nPalette, int x1, int y1, int x2, dassert(nTile >= 0 && nTile < kMaxTiles); int width = tilesiz[nTile].x; int height = tilesiz[nTile].y; - int bx1 = DecBy(rect1.x1+1, width); - int by1 = DecBy(rect1.y1+1, height); - int bx2 = IncBy(rect1.x2-1, width); - int by2 = IncBy(rect1.y2-1, height); + int bx1 = DecBy(rect1.x0+1, width); + int by1 = DecBy(rect1.y0+1, height); + int bx2 = IncBy(rect1.x1-1, width); + int by2 = IncBy(rect1.y1-1, height); for (int x = bx1; x < bx2; x += width) for (int y = by1; y < by2; y += height) rotatesprite(x<<16, y<<16, 65536, 0, nTile, nShade, nPalette, 64+16+8, x1, y1, x2-1, y2-1); @@ -2204,13 +2204,11 @@ void viewProcessSprites(int32_t cX, int32_t cY, int32_t cZ, int32_t cA, int32_t break; case 1: { -#ifdef USE_OPENGL - if (videoGetRenderMode() >= REND_POLYMOST && usemodels && md_tilehasmodel(pTSprite->picnum, pTSprite->pal) >= 0 && !(spriteext[nSprite].flags&SPREXT_NOTMD)) + if (tilehasmodelorvoxel(pTSprite->picnum, pTSprite->pal) && !(spriteext[nSprite].flags&SPREXT_NOTMD)) { pTSprite->cstat &= ~4; break; } -#endif int dX = cX - pTSprite->x; int dY = cY - pTSprite->y; RotateVector(&dX, &dY, 128-pTSprite->ang); @@ -2228,13 +2226,11 @@ void viewProcessSprites(int32_t cX, int32_t cY, int32_t cZ, int32_t cA, int32_t } case 2: { -#ifdef USE_OPENGL - if (videoGetRenderMode() >= REND_POLYMOST && usemodels && md_tilehasmodel(pTSprite->picnum, pTSprite->pal) >= 0 && !(spriteext[nSprite].flags&SPREXT_NOTMD)) + if (tilehasmodelorvoxel(pTSprite->picnum, pTSprite->pal) && !(spriteext[nSprite].flags&SPREXT_NOTMD)) { pTSprite->cstat &= ~4; break; } -#endif int dX = cX - pTSprite->x; int dY = cY - pTSprite->y; RotateVector(&dX, &dY, 128-pTSprite->ang); @@ -2270,6 +2266,7 @@ void viewProcessSprites(int32_t cX, int32_t cY, int32_t cZ, int32_t cA, int32_t if ((pTSprite->hitag&16) == 0) { pTSprite->cstat |= 48; + pTSprite->cstat &= ~(4|8); pTSprite->yoffset += picanm[pTSprite->picnum].yofs; pTSprite->picnum = voxelIndex[pTSprite->picnum]; if (!voxoff[pTSprite->picnum]) @@ -2289,9 +2286,15 @@ void viewProcessSprites(int32_t cX, int32_t cY, int32_t cZ, int32_t cA, int32_t nAnim--; } - if (usevoxels && videoGetRenderMode() != REND_POLYMER && tiletovox[pTSprite->picnum] != -1) + if ((pTSprite->cstat&48) != 48) { - pTSprite->yoffset += picanm[pTSprite->picnum].yofs; + int nAnimTile = pTSprite->picnum + animateoffs_replace(pTSprite->picnum, 32768+pTSprite->owner); + + if (usevoxels && videoGetRenderMode() != REND_POLYMER && tiletovox[nAnimTile] != -1) + { + pTSprite->yoffset += picanm[nAnimTile].yofs; + pTSprite->xoffset += picanm[nAnimTile].xofs; + } } sectortype *pSector = §or[pTSprite->sectnum]; diff --git a/source/blood/src/weapon.cpp b/source/blood/src/weapon.cpp index 505680dca..397eecf44 100644 --- a/source/blood/src/weapon.cpp +++ b/source/blood/src/weapon.cpp @@ -1382,41 +1382,79 @@ void FireVoodoo(int nTrigger, PLAYER *pPlayer) void AltFireVoodoo(int nTrigger, PLAYER *pPlayer) { - if (nTrigger != 2) - return; - //int nAmmo = pPlayer->at181[9]; - int nCount = ClipHigh(pPlayer->at181[9], pPlayer->at1da); - if (nCount > 0) - { - int v4 = pPlayer->at181[9] - (pPlayer->at181[9] / nCount)*nCount; - for (int i = 0; i < pPlayer->at1da; i++) - { - int nTarget = pPlayer->at1de[i]; - spritetype *pTarget = &sprite[nTarget]; - if (v4 > 0) - v4--; - int nDist = approxDist(pTarget->x-pPlayer->pSprite->x, pTarget->y-pPlayer->pSprite->y); - if (nDist > 0 && nDist < 51200) + + if (nTrigger == 2) { + + // by NoOne: trying to simulate v1.0x voodoo here. + // dunno how exactly it works, but at least it not spend all the ammo on alt fire + if (gGameOptions.weaponsV10x && !VanillaMode() && !DemoRecordStatus()) { + int nCount = ClipHigh(pPlayer->at181[9], pPlayer->at1da); + if (nCount > 0) { - int vc = pPlayer->at181[9]>>3; - int v8 = pPlayer->at181[9]<<1; - int nDamage = (v8+Random2(vc))<<4; - nDamage = (nDamage*((51200-nDist)+1))/51200; - nDamage = actDamageSprite(pPlayer->at5b, pTarget, DAMAGE_TYPE_5, nDamage); - UseAmmo(pPlayer, 9, nDamage); - if (pTarget->type >= kDudePlayer1 && pTarget->type <= kDudePlayer8) + for (int i = 0; i < pPlayer->at1da; i++) { - PLAYER *pOtherPlayer = &gPlayer[pTarget->type-kDudePlayer1]; - if (!pOtherPlayer->at31a || !powerupCheck(pOtherPlayer,14)) - powerupActivate(pOtherPlayer, 28); + int nTarget = pPlayer->at1de[i]; + spritetype* pTarget = &sprite[nTarget]; + + int nDist = approxDist(pTarget->x - pPlayer->pSprite->x, pTarget->y - pPlayer->pSprite->y); + if (nDist > 0 && nDist < 51200) + { + int vc = pPlayer->at181[9] >> 3; + int v8 = pPlayer->at181[9] << 1; + int nDamage = (v8 + Random(vc)) << 4; + nDamage = (nDamage * ((51200 - nDist) + 1)) / 51200; + nDamage = actDamageSprite(pPlayer->at5b, pTarget, DAMAGE_TYPE_5, nDamage); + + if (pTarget->type >= kDudePlayer1 && pTarget->type <= kDudePlayer8) + { + PLAYER* pOtherPlayer = &gPlayer[pTarget->type - kDudePlayer1]; + if (!pOtherPlayer->at31a || !powerupCheck(pOtherPlayer, 14)) + powerupActivate(pOtherPlayer, 28); + } + fxSpawnBlood(pTarget, 0); + } + } + } + + UseAmmo(pPlayer, 9, 20); + pPlayer->atc3 = 0; + return; + } + + //int nAmmo = pPlayer->at181[9]; + int nCount = ClipHigh(pPlayer->at181[9], pPlayer->at1da); + if (nCount > 0) + { + int v4 = pPlayer->at181[9] - (pPlayer->at181[9] / nCount) * nCount; + for (int i = 0; i < pPlayer->at1da; i++) + { + int nTarget = pPlayer->at1de[i]; + spritetype* pTarget = &sprite[nTarget]; + if (v4 > 0) + v4--; + int nDist = approxDist(pTarget->x - pPlayer->pSprite->x, pTarget->y - pPlayer->pSprite->y); + if (nDist > 0 && nDist < 51200) + { + int vc = pPlayer->at181[9] >> 3; + int v8 = pPlayer->at181[9] << 1; + int nDamage = (v8 + Random2(vc)) << 4; + nDamage = (nDamage * ((51200 - nDist) + 1)) / 51200; + nDamage = actDamageSprite(pPlayer->at5b, pTarget, DAMAGE_TYPE_5, nDamage); + UseAmmo(pPlayer, 9, nDamage); + if (pTarget->type >= kDudePlayer1 && pTarget->type <= kDudePlayer8) + { + PLAYER* pOtherPlayer = &gPlayer[pTarget->type - kDudePlayer1]; + if (!pOtherPlayer->at31a || !powerupCheck(pOtherPlayer, 14)) + powerupActivate(pOtherPlayer, 28); + } + fxSpawnBlood(pTarget, 0); } - fxSpawnBlood(pTarget, 0); } } + UseAmmo(pPlayer, 9, pPlayer->at181[9]); + pPlayer->atcb[10] = 0; + pPlayer->atc3 = -1; } - UseAmmo(pPlayer, 9, pPlayer->at181[9]); - pPlayer->atcb[10] = 0; - pPlayer->atc3 = -1; } void DropVoodoo(int nTrigger, PLAYER *pPlayer) @@ -2357,9 +2395,11 @@ void WeaponProcess(PLAYER *pPlayer) return; case 5: if (powerupCheck(pPlayer, 17)) - StartQAV(pPlayer, 122, nClientAltFireNapalm, 0); + // by NoOne: allow napalm launcher alt fire act like in v1.0x versions + if (gGameOptions.weaponsV10x && !VanillaMode() && !DemoRecordStatus()) StartQAV(pPlayer, 123, nClientFireNapalm2, 0); + else StartQAV(pPlayer, 122, nClientAltFireNapalm, 0); else - StartQAV(pPlayer, 91, nClientAltFireNapalm, 0); + StartQAV(pPlayer, 91, (gGameOptions.weaponsV10x && !VanillaMode() && !DemoRecordStatus()) ? nClientFireNapalm : nClientAltFireNapalm, 0); return; case 2: if (CheckAmmo(pPlayer, 1, 8)) diff --git a/source/build/include/baselayer.h b/source/build/include/baselayer.h index 6c0656b98..0532fa3ab 100644 --- a/source/build/include/baselayer.h +++ b/source/build/include/baselayer.h @@ -29,6 +29,7 @@ extern char modechange; extern char nogl; extern int32_t vsync; +extern int32_t swapcomplete; extern int32_t r_borderless; extern int32_t r_displayindex; diff --git a/source/build/include/build.h b/source/build/include/build.h index 60a029454..74a5af36a 100644 --- a/source/build/include/build.h +++ b/source/build/include/build.h @@ -178,7 +178,7 @@ void yax_updategrays(int32_t posze); # else // More user tag hijacking: lotag/extra. :/ # define YAX_PTRNEXTWALL(Ptr, Wall, Cf) (*(int16_t *)(&Ptr[Wall].lotag + (bloodhack ? 1 : 2)*Cf)) -# define YAX_NEXTWALLDEFAULT(Cf) (((Cf)==YAX_CEILING) ? 0 : -1) +# define YAX_NEXTWALLDEFAULT(Cf) (bloodhack ? 0 : ((Cf)==YAX_CEILING) ? 0 : -1) extern int16_t yax_bunchnum[MAXSECTORS][2]; extern int16_t yax_nextwall[MAXWALLS][2]; # endif @@ -948,6 +948,9 @@ static FORCE_INLINE int32_t videoGetRenderMode(void) #endif } +extern int32_t bloodhack; +extern int32_t blooddemohack; + /************************************************************************* POSITION VARIABLES: diff --git a/source/build/include/buildtypes.h b/source/build/include/buildtypes.h index 86a6040eb..4661adfaf 100644 --- a/source/build/include/buildtypes.h +++ b/source/build/include/buildtypes.h @@ -182,17 +182,19 @@ typedef struct union { struct { - StructTracker(Sprite, int16_t) xvel /*index*/, yvel, zvel; + union { + StructTracker(Sprite, int16_t) xvel; + StructTracker(Sprite, int16_t) index; + }; + StructTracker(Sprite, int16_t) yvel, zvel; }; - StructTracker(Sprite, int16_t) index; - vec3_16_t vel; + vec3_16_t vel; }; - union { - struct { - StructTracker(Sprite, int16_t) lotag /*type*/, hitag; - }; - StructTracker(Sprite, int16_t) type; - }; + union { + StructTracker(Sprite, int16_t) lotag; + StructTracker(Sprite, int16_t) type; + }; + StructTracker(Sprite, int16_t) hitag; StructTracker(Sprite, int16_t) extra; } StructName(spritetypev7); diff --git a/source/build/include/clockticks.hpp b/source/build/include/clockticks.hpp index 8c98200d5..f116f9fc0 100644 --- a/source/build/include/clockticks.hpp +++ b/source/build/include/clockticks.hpp @@ -131,7 +131,6 @@ public: explicit operator uint32_t() const { return wholeTicks; }; explicit operator int32_t() const { return wholeTicks; }; - int32_t Ticks() const { return wholeTicks; } private: //POGO: wholeTicks must be first in member-order to ensure the address of diff --git a/source/build/include/polymost.h b/source/build/include/polymost.h index c1cc15321..a60132ed1 100644 --- a/source/build/include/polymost.h +++ b/source/build/include/polymost.h @@ -160,7 +160,7 @@ static FORCE_INLINE int polymost_is_npotmode(void) #ifdef NEW_MAP_FORMAT g_loadedMapVersion < 10 && #endif - (playing_rr? r_npotwallmode == 1 : r_npotwallmode != 0); // I have no idea which one is more correct... + r_npotwallmode; } static inline float polymost_invsqrt_approximation(float x) diff --git a/source/build/src/cache1d.cpp b/source/build/src/cache1d.cpp index 1c1673476..9595bd7ba 100644 --- a/source/build/src/cache1d.cpp +++ b/source/build/src/cache1d.cpp @@ -1111,18 +1111,18 @@ int32_t kopen4load(const char *filename, char searchfirst) char g_modDir[BMAX_PATH] = "/"; -buildvfs_kfd kopen4loadfrommod(const char* fileName, char searchfirst) +buildvfs_kfd kopen4loadfrommod(const char *fileName, char searchfirst) { - buildvfs_kfd kFile = buildvfs_kfd_invalid; + buildvfs_kfd kFile = buildvfs_kfd_invalid; - if (g_modDir[0] != '/' || g_modDir[1] != 0) - { - static char staticFileName[BMAX_PATH]; - Bsnprintf(staticFileName, sizeof(staticFileName), "%s/%s", g_modDir, fileName); - kFile = kopen4load(staticFileName, searchfirst); - } + if (g_modDir[0] != '/' || g_modDir[1] != 0) + { + static char staticFileName[BMAX_PATH]; + Bsnprintf(staticFileName, sizeof(staticFileName), "%s/%s", g_modDir, fileName); + kFile = kopen4load(staticFileName, searchfirst); + } - return (kFile == buildvfs_kfd_invalid) ? kopen4load(fileName, searchfirst) : kFile; + return (kFile == buildvfs_kfd_invalid) ? kopen4load(fileName, searchfirst) : kFile; } int32_t kread_internal(int32_t handle, void *buffer, int32_t leng, const uint8_t *arraygrp, const intptr_t *arrayhan, int32_t *arraypos) diff --git a/source/build/src/clip.cpp b/source/build/src/clip.cpp index 9e1d601ed..86cd0df0b 100644 --- a/source/build/src/clip.cpp +++ b/source/build/src/clip.cpp @@ -794,15 +794,15 @@ static int cliptestsector(int const dasect, int const nextsect, int32_t const fl if (blooddemohack) { - int32_t daz = getflorzofslope(dasect, pos.x, pos.y); - int32_t daz2 = getflorzofslope(nextsect, pos.x, pos.y); + int32_t daz = getflorzofslope(dasect, pos.x, pos.y); + int32_t daz2 = getflorzofslope(nextsect, pos.x, pos.y); - if (daz2 < daz-(1<<8) && (sec2->floorstat&1) == 0) - if (posz >= daz2-(flordist-1)) return 1; - daz = getceilzofslope(dasect, pos.x, pos.y); - daz2 = getceilzofslope(nextsect, pos.x, pos.y); - if (daz2 > daz+(1<<8) && (sec2->ceilingstat&1) == 0) - if (posz <= daz2+(ceildist-1)) return 1; + if (daz2 < daz-(1<<8) && (sec2->floorstat&1) == 0) + if (posz >= daz2-(flordist-1)) return 1; + daz = getceilzofslope(dasect, pos.x, pos.y); + daz2 = getceilzofslope(nextsect, pos.x, pos.y); + if (daz2 > daz+(1<<8) && (sec2->ceilingstat&1) == 0) + if (posz <= daz2+(ceildist-1)) return 1; return 0; } @@ -817,7 +817,6 @@ static int cliptestsector(int const dasect, int const nextsect, int32_t const fl return 1; auto const sec = (usectorptr_t)§or[dasect]; - int32_t daz = sec->floorz; int32_t dacz = sec->ceilingz; @@ -1373,17 +1372,17 @@ int32_t clipmove(vec3_t * const pos, int16_t * const sectnum, int32_t xvect, int do { if (!blooddemohack) - for (native_t i=clipnum-1;i>=0;--i) - { - if (!bitmap_test(clipignore, i) && clipinsideboxline(pos->x, pos->y, clipit[i].x1, clipit[i].y1, clipit[i].x2, clipit[i].y2, walldist)) + for (native_t i=clipnum-1;i>=0;--i) { - vec2_t const vec = pos->vec2; - keepaway(&pos->x, &pos->y, i); - if (inside(pos->x,pos->y, *sectnum) != 1) - pos->vec2 = vec; - break; + if (!bitmap_test(clipignore, i) && clipinsideboxline(pos->x, pos->y, clipit[i].x1, clipit[i].y1, clipit[i].x2, clipit[i].y2, walldist)) + { + vec2_t const vec = pos->vec2; + keepaway(&pos->x, &pos->y, i); + if (inside(pos->x,pos->y, *sectnum) != 1) + pos->vec2 = vec; + break; + } } - } vec2_t vec = goal; @@ -1392,8 +1391,8 @@ int32_t clipmove(vec3_t * const pos, int16_t * const sectnum, int32_t xvect, int vec2_t const clipr = { clipit[hitwall].x2 - clipit[hitwall].x1, clipit[hitwall].y2 - clipit[hitwall].y1 }; int64_t const templl = maybe_truncate_to_int32((int64_t)clipr.x * clipr.x + (int64_t)clipr.y * clipr.y); - if (templl > 0) - { + if (templl > 0) + { int64_t const templl2 = maybe_truncate_to_int32((int64_t)(goal.x-vec.x)*clipr.x + (int64_t)(goal.y-vec.y)*clipr.y); int32_t const i = ((llabs(templl2)>>11) < templl) ? divscale64(templl2, templl, 20) : 0; @@ -1411,7 +1410,7 @@ int32_t clipmove(vec3_t * const pos, int16_t * const sectnum, int32_t xvect, int if (blooddemohack == 1) updatesector(pos->x, pos->y, sectnum); return clipReturn; - } + } } keepaway(&goal.x, &goal.y, hitwall); @@ -1424,7 +1423,7 @@ int32_t clipmove(vec3_t * const pos, int16_t * const sectnum, int32_t xvect, int } if (!blooddemohack) - clipupdatesector(vec, sectnum, rad); + clipupdatesector(vec, sectnum, rad); pos->x = vec.x; pos->y = vec.y; @@ -1437,7 +1436,7 @@ int32_t clipmove(vec3_t * const pos, int16_t * const sectnum, int32_t xvect, int if (inside(pos->x, pos->y, clipsectorlist[j]) == 1) { *sectnum = clipsectorlist[j]; - return clipReturn; + return clipReturn; } int32_t tempint2, tempint1 = INT32_MAX; @@ -1705,13 +1704,13 @@ restart_grand: int32_t daz, daz2; closest = { pos->x, pos->y }; if (!blooddemohack) - getsectordist(closest, k, &closest); + getsectordist(closest, k, &closest); getzsofslope(k,closest.x,closest.y,&daz,&daz2); int32_t fz, cz; closest = { pos->x, pos->y }; if (!blooddemohack) - getsectordist(closest, sectq[clipinfo[curidx].qend], &closest); + getsectordist(closest, sectq[clipinfo[curidx].qend], &closest); getzsofslope(sectq[clipinfo[curidx].qend],closest.x,closest.y,&cz,&fz); const int hitwhat = (curspr-(uspritetype *)sprite)+49152; @@ -1797,7 +1796,7 @@ restart_grand: int32_t daz, daz2; closest = { pos->x, pos->y }; if (!blooddemohack) - getsectordist(closest, k, &closest); + getsectordist(closest, k, &closest); getzsofslope(k, closest.x,closest.y, &daz,&daz2); #ifdef HAVE_CLIPSHAPE_FEATURE @@ -1807,7 +1806,7 @@ restart_grand: closest = { pos->x, pos->y }; if (!blooddemohack) - getsectordist(closest, sectq[clipinfo[curidx].qend], &closest); + getsectordist(closest, sectq[clipinfo[curidx].qend], &closest); getzsofslope(sectq[clipinfo[curidx].qend],closest.x,closest.y,&cz,&fz); if ((sec->ceilingstat&1)==0) @@ -2441,19 +2440,19 @@ restart_grand: if ((sv->z > intz) == ((cstat&8)==0)) continue; if (!blooddemohack) { - // Abyss crash prevention code ((intz-sv->z)*zx overflowing a 8-bit word) - // PK: the reason for the crash is not the overflowing (even if it IS a problem; - // signed overflow is undefined behavior in C), but rather the idiv trap when - // the resulting quotient doesn't fit into a *signed* 32-bit integer. - zz = (uint32_t)(intz-sv->z) * vx; - intx = sv->x+scale(zz,1,vz); - zz = (uint32_t)(intz-sv->z) * vy; - inty = sv->y+scale(zz,1,vz); + // Abyss crash prevention code ((intz-sv->z)*zx overflowing a 8-bit word) + // PK: the reason for the crash is not the overflowing (even if it IS a problem; + // signed overflow is undefined behavior in C), but rather the idiv trap when + // the resulting quotient doesn't fit into a *signed* 32-bit integer. + zz = (uint32_t)(intz-sv->z) * vx; + intx = sv->x+scale(zz,1,vz); + zz = (uint32_t)(intz-sv->z) * vy; + inty = sv->y+scale(zz,1,vz); } else { - intx = sv->x+scale(intz-sv->z,vx,vz); - inty = sv->y+scale(intz-sv->z,vy,vz); + intx = sv->x+scale(intz-sv->z,vx,vz); + inty = sv->y+scale(intz-sv->z,vy,vz); } if (klabs(intx-sv->x)+klabs(inty-sv->y) > klabs((hit->pos.x)-sv->x)+klabs((hit->pos.y)-sv->y)) diff --git a/source/build/src/common.cpp b/source/build/src/common.cpp index c18b38c3f..9cfa16179 100644 --- a/source/build/src/common.cpp +++ b/source/build/src/common.cpp @@ -223,7 +223,7 @@ int32_t ldist(const void *s1, const void *s2) { auto sp1 = (vec2_t const *)s1; auto sp2 = (vec2_t const *)s2; - return sepldist(sp1->x - sp2->x, sp1->y - sp2->y); + return sepldist(sp1->x - sp2->x, sp1->y - sp2->y) + (blooddemohack ? 1 : 0); } int32_t dist(const void *s1, const void *s2) diff --git a/source/build/src/defs.cpp b/source/build/src/defs.cpp index ccd401e38..9ebc7bdcb 100644 --- a/source/build/src/defs.cpp +++ b/source/build/src/defs.cpp @@ -265,10 +265,10 @@ static int32_t Defs_ImportTileFromTexture(char const * const fn, int32_t const t if (artstatus < 0) return artstatus<<8; - int32_t picanmdisk; - Bmemcpy(&picanmdisk, &kpzbuf[20], sizeof(int32_t)); - picanmdisk = B_LITTLE32(picanmdisk); - tileConvertAnimFormat(tile, picanmdisk); + int32_t picanmdisk; + Bmemcpy(&picanmdisk, &kpzbuf[20], sizeof(int32_t)); + picanmdisk = B_LITTLE32(picanmdisk); + tileConvertAnimFormat(tile, picanmdisk); int32_t const xsiz = B_LITTLE16(B_UNBUF16(&kpzbuf[16])); int32_t const ysiz = B_LITTLE16(B_UNBUF16(&kpzbuf[18])); diff --git a/source/build/src/engine.cpp b/source/build/src/engine.cpp index 6d4887373..16f8c251f 100644 --- a/source/build/src/engine.cpp +++ b/source/build/src/engine.cpp @@ -204,6 +204,7 @@ static fix16_t global100horiz; // (-100..300)-scale horiz (the one passed to dr int32_t(*getpalookup_replace)(int32_t davis, int32_t dashade) = NULL; int32_t bloodhack = 0; +int32_t blooddemohack = 0; // adapted from build.c static void getclosestpointonwall_internal(vec2_t const p, int32_t const dawall, vec2_t *const closest) @@ -1668,9 +1669,7 @@ static inline int findUnusedTile(void) static void classicScanSector(int16_t startsectnum) { if (startsectnum < 0) - { return; - } if (automapping) show2dsector[startsectnum>>3] |= pow2char[startsectnum&7]; @@ -3386,7 +3385,6 @@ static inline void setupslopevlin_alsotrans(int32_t logylogx, intptr_t bufplc, i static void tslopevlin(uint8_t *p, const intptr_t *slopalptr, bssize_t cnt, int32_t bx, int32_t by) { const char *const A_C_RESTRICT buf = ggbuf; - const char *const A_C_RESTRICT pal = ggpal; const char *const A_C_RESTRICT trans = paletteGetBlendTable(0); const int32_t bzinc = (asm1>>3), pinc = ggpinc; @@ -3418,7 +3416,6 @@ static void tslopevlin(uint8_t *p, const intptr_t *slopalptr, bssize_t cnt, int3 static void mslopevlin(uint8_t *p, const intptr_t *slopalptr, bssize_t cnt, int32_t bx, int32_t by) { const char *const A_C_RESTRICT buf = ggbuf; - const char *const A_C_RESTRICT pal = ggpal; const int32_t bzinc = (asm1>>3), pinc = ggpinc; const uint32_t xtou = globalx3, ytov = globaly3; @@ -6102,10 +6099,10 @@ draw_as_face_sprite: if (x == rx) return; } - if (loadvoxel_replace) for (i=0; i= 0) prevspritestat[headspritestat[MAXSTATUS]] = -1; - else + else if (!blooddemohack) tailspritefree = -1; do_insertsprite_at_headofstat(blanktouse, statnum); @@ -7806,15 +7807,20 @@ int32_t deletesprite(int16_t spritenum) sprite[spritenum].sectnum = MAXSECTORS; // insert at tail of status freelist - prevspritestat[spritenum] = tailspritefree; - nextspritestat[spritenum] = -1; - if (tailspritefree >= 0) - nextspritestat[tailspritefree] = spritenum; + if (blooddemohack) + do_insertsprite_at_headofstat(spritenum, MAXSTATUS); else - headspritestat[MAXSTATUS] = spritenum; - sprite[spritenum].statnum = MAXSTATUS; + { + prevspritestat[spritenum] = tailspritefree; + nextspritestat[spritenum] = -1; + if (tailspritefree >= 0) + nextspritestat[tailspritefree] = spritenum; + else + headspritestat[MAXSTATUS] = spritenum; + sprite[spritenum].statnum = MAXSTATUS; - tailspritefree = spritenum; + tailspritefree = spritenum; + } Numsprites--; return 0; @@ -9717,7 +9723,7 @@ int32_t engineLoadBoard(const char *filename, char flags, vec3_t *dapos, int16_t { if (loadboard_replace) return loadboard_replace(filename, flags, dapos, daang, dacursectnum); - int32_t fil, i; + int32_t i; int16_t numsprites; const char myflags = flags&(~3); @@ -10706,8 +10712,46 @@ void vox_undefine(int32_t const tile) // // See http://fabiensanglard.net/duke3d/build_engine_internals.php, // "Inside details" for the idea behind the algorithm. + +int32_t inside_old(int32_t x, int32_t y, int16_t sectnum) +{ + if (sectnum >= 0 && sectnum < numsectors) + { + uint32_t cnt = 0; + auto wal = (uwallptr_t)&wall[sector[sectnum].wallptr]; + int wallsleft = sector[sectnum].wallnum; + + do + { + // Get the x and y components of the [tested point]-->[wall + // point{1,2}] vectors. + vec2_t v1 = { wal->x - x, wal->y - y }; + auto const &wal2 = *(uwallptr_t)&wall[wal->point2]; + vec2_t v2 = { wal2.x - x, wal2.y - y }; + + // If their signs differ[*], ... + // + // [*] where '-' corresponds to <0 and '+' corresponds to >=0. + // Equivalently, the branch is taken iff + // y1 != y2 AND y_m <= y < y_M, + // where y_m := min(y1, y2) and y_M := max(y1, y2). + if ((v1.y^v2.y) < 0) + cnt ^= (((v1.x^v2.x) >= 0) ? v1.x : (v1.x*v2.y-v2.x*v1.y)^v2.y); + + wal++; + } + while (--wallsleft); + + return cnt>>31; + } + + return -1; +} + int32_t inside(int32_t x, int32_t y, int16_t sectnum) { + if (blooddemohack) + return inside_old(x, y, sectnum); if ((unsigned)sectnum < (unsigned)numsectors) { uint32_t cnt1 = 0, cnt2 = 0; @@ -12257,6 +12301,7 @@ void renderPrepareMirror(int32_t dax, int32_t day, int32_t daz, fix16_t daang, f #endif } + // // completemirror // @@ -12373,7 +12418,8 @@ int32_t getceilzofslopeptr(usectorptr_t sec, int32_t dax, int32_t day) if (i == 0) return sec->ceilingz; int const j = dmulscale3(d.x, day-w.y, -d.y, dax-w.x); - return sec->ceilingz + (scale(sec->ceilingheinum,j>>1,i)<<1); + int const shift = blooddemohack ? 0 : 1; + return sec->ceilingz + (scale(sec->ceilingheinum,j>>shift,i)<floorz; int const j = dmulscale3(d.x, day-w.y, -d.y, dax-w.x); - return sec->floorz + (scale(sec->floorheinum,j>>1,i)<<1); + int const shift = blooddemohack ? 0 : 1; + return sec->floorz + (scale(sec->floorheinum,j>>shift,i)<y, -d.y,dax-wal->x); + int const shift = blooddemohack ? 0 : 1; if (sec->ceilingstat&2) - *ceilz += scale(sec->ceilingheinum,j>>1,i)<<1; + *ceilz += scale(sec->ceilingheinum,j>>shift,i)<floorstat&2) - *florz += scale(sec->floorheinum,j>>1,i)<<1; + *florz += scale(sec->floorheinum,j>>shift,i)< static FORCE_INLINE void tileUpdatePicnum(T * const tileptr, int const obj) { auto &tile = *tileptr; - if (playing_blood || picanm[tile].sf & PICANM_ANIMTYPE_MASK) tile += animateoffs(tile, obj); + if (picanm[tile].sf & PICANM_ANIMTYPE_MASK) + tile += animateoffs(tile, obj); if (((obj & 16384) == 16384) && (globalorientation & CSTAT_WALL_ROTATE_90) && rottile[tile].newtile != -1) tile = rottile[tile].newtile; diff --git a/source/build/src/palette.cpp b/source/build/src/palette.cpp index 9d351d81f..cb9e05567 100644 --- a/source/build/src/palette.cpp +++ b/source/build/src/palette.cpp @@ -209,8 +209,8 @@ void paletteLoadFromDisk(void) return; } - auto fil = kopen4load("palette.dat", 0); - if (fil == buildvfs_kfd_invalid) + buildvfs_kfd fil; + if ((fil = kopen4load("palette.dat", 0)) == buildvfs_kfd_invalid) return; @@ -773,7 +773,7 @@ void videoSetPalette(char dabrightness, uint8_t dapalid, uint8_t flags) } videoSetGamma(); - j = (!gammabrightness || (flags&32) != 0) ? curbrightness : 0; + j = !gammabrightness ? curbrightness : 0; for (i=0; i<256; i++) { @@ -791,7 +791,7 @@ void videoSetPalette(char dabrightness, uint8_t dapalid, uint8_t flags) } #ifdef USE_OPENGL - if ((flags&32) != 0 && videoGetRenderMode() == REND_POLYMOST) + if ((flags&32) != 0 && videoGetRenderMode() == REND_POLYMOST && playing_rr) r_brightnesshack = j; else r_brightnesshack = 0; diff --git a/source/build/src/polymost.cpp b/source/build/src/polymost.cpp index d92acfb80..00e5ab1aa 100644 --- a/source/build/src/polymost.cpp +++ b/source/build/src/polymost.cpp @@ -4186,7 +4186,7 @@ static void polymost_drawalls(int32_t const bunch) drawpoly_blend = 0; int32_t const sectnum = thesector[bunchfirst[bunch]]; - usectortype const * const sec = (usectortype *)§or[sectnum]; + auto const sec = (usectorptr_t)§or[sectnum]; float const fglobalang = fix16_to_float(qglobalang); polymost_outputGLDebugMessage(3, "polymost_drawalls(bunch:%d)", bunch); @@ -4196,10 +4196,10 @@ static void polymost_drawalls(int32_t const bunch) { int32_t const wallnum = thewall[z]; - auto const wal = (uwalltype *)&wall[wallnum]; - auto const wal2 = (uwalltype *)&wall[wal->point2]; + auto const wal = (uwallptr_t)&wall[wallnum]; + auto const wal2 = (uwallptr_t)&wall[wal->point2]; int32_t const nextsectnum = wal->nextsector; - auto const nextsec = nextsectnum>=0 ? (usectortype *)§or[nextsectnum] : NULL; + auto const nextsec = nextsectnum>=0 ? (usectorptr_t)§or[nextsectnum] : NULL; //Offset&Rotate 3D coordinates to screen 3D space vec2f_t walpos = { (float)(wal->x-globalposx), (float)(wal->y-globalposy) }; @@ -4720,66 +4720,67 @@ static void polymost_drawalls(int32_t const bunch) { - //Hack to draw color rectangle above sky when looking up... - xtex.d = xtex.u = xtex.v = 0; - ytex.d = gxyaspect * (1.0 / -262144.0); - ytex.u = 0; - ytex.v = 0; + //Hack to draw color rectangle above sky when looking up... + xtex.d = xtex.u = xtex.v = 0; - otex.d = -ghoriz * ytex.d; - otex.u = 0; - otex.v = 0; + ytex.d = gxyaspect * (1.0 / -262144.0); + ytex.u = 0; + ytex.v = 0; - o.y = -vv[0]/vv[1]; + otex.d = -ghoriz * ytex.d; + otex.u = 0; + otex.v = 0; - if ((o.y < cy0) && (o.y < cy1)) - polymost_domost(x1,o.y,x0,o.y); - else if ((o.y < cy0) != (o.y < cy1)) - { - /* cy1 cy0 - // / \ - //oy---------- oy--------- - // / \ - // cy0 cy1 */ - o.x = (o.y-cy0)*(x1-x0)/(cy1-cy0) + x0; - if (o.y < cy0) + o.y = -vv[0]/vv[1]; + + if ((o.y < cy0) && (o.y < cy1)) + polymost_domost(x1,o.y,x0,o.y); + else if ((o.y < cy0) != (o.y < cy1)) { - polymost_domost(o.x,o.y,x0,o.y); - polymost_domost(x1,cy1,o.x,o.y); + /* cy1 cy0 + // / \ + //oy---------- oy--------- + // / \ + // cy0 cy1 */ + o.x = (o.y-cy0)*(x1-x0)/(cy1-cy0) + x0; + if (o.y < cy0) + { + polymost_domost(o.x,o.y,x0,o.y); + polymost_domost(x1,cy1,o.x,o.y); + } + else + { + polymost_domost(o.x,o.y,x0,cy0); + polymost_domost(x1,o.y,o.x,o.y); + } } else - { - polymost_domost(o.x,o.y,x0,cy0); - polymost_domost(x1,o.y,o.x,o.y); - } + polymost_domost(x1,cy1,x0,cy0); } else - polymost_domost(x1,cy1,x0,cy0); - } - else - skyclamphack = 0; + skyclamphack = 0; - xtex.d = xtex.v = 0; - ytex.d = ytex.u = 0; - otex.d = dd; - xtex.u = otex.d * (t * double(((uint64_t)xdimscale * yxaspect) * viewingrange)) * - (1.0 / (16384.0 * 65536.0 * 65536.0 * 5.0 * 1024.0)); - ytex.v = vv[1]; - otex.v = r_parallaxskypanning ? vv[0] + dd*(float)sec->ceilingypanning*(float)i*(1.f/256.f) : vv[0]; + xtex.d = xtex.v = 0; + ytex.d = ytex.u = 0; + otex.d = dd; + xtex.u = otex.d * (t * double(((uint64_t)xdimscale * yxaspect) * viewingrange)) * + (1.0 / (16384.0 * 65536.0 * 65536.0 * 5.0 * 1024.0)); + ytex.v = vv[1]; + otex.v = r_parallaxskypanning ? vv[0] + dd*(float)sec->ceilingypanning*(float)i*(1.f/256.f) : vv[0]; int const npot = (1<<(picsiz[globalpicnum]&15)) != tilesiz[globalpicnum].x; int const xpanning = (r_parallaxskypanning?sec->ceilingxpanning:0); - i = globalpicnum; - float const r = (cy1-cy0)/(x1-x0); //slope of line - o.y = fviewingrange/(ghalfx*256.f); o.z = 1.f/o.y; + i = globalpicnum; + float const r = (cy1-cy0)/(x1-x0); //slope of line + o.y = fviewingrange/(ghalfx*256.f); o.z = 1.f/o.y; - int y = ((int32_t)(((x0-ghalfx)*o.y)+fglobalang)>>(11-dapskybits)); - float fx = x0; - do - { - globalpicnum = dapskyoff[y&((1<>(11-dapskybits)); + float fx = x0; + do + { + globalpicnum = dapskyoff[y&((1< x1) { fx = x1; i = -1; } + y++; + o.x = fx; fx = (((float) (y<<(11-dapskybits))-fglobalang))*o.z+ghalfx; + if (fx > x1) { fx = x1; i = -1; } - pow2xsplit = 0; polymost_domost(fx,(fx-x0)*r+cy0,o.x,(o.x-x0)*r+cy0); //ceil - } - while (i >= 0); + pow2xsplit = 0; polymost_domost(fx,(fx-x0)*r+cy0,o.x,(o.x-x0)*r+cy0); //ceil + } + while (i >= 0); } ghoriz = ghorizbak; @@ -5104,12 +5105,12 @@ static void polymost_drawalls(int32_t const bunch) } if (((ofy0 < fy0) || (ofy1 < fy1)) && (!((sec->floorstat§or[nextsectnum].floorstat)&1))) { - uwalltype *nwal; + uwallptr_t nwal; if (!(wal->cstat&2)) nwal = wal; else { - nwal = (uwalltype *)&wall[wal->nextwall]; + nwal = (uwallptr_t)&wall[wal->nextwall]; otex.u += (float)(nwal->xpanning - wal->xpanning) * otex.d; xtex.u += (float)(nwal->xpanning - wal->xpanning) * xtex.d; ytex.u += (float)(nwal->xpanning - wal->xpanning) * ytex.d; @@ -5261,7 +5262,7 @@ void polymost_scansector(int32_t sectnum) #endif for (bssize_t z=headspritesect[sectnum]; z>=0; z=nextspritesect[z]) { - uspritetype const * const spr = (uspritetype *)&sprite[z]; + auto const spr = (uspriteptr_t)&sprite[z]; if ((spr->cstat & 0x8000 && !showinvisibility) || spr->xrepeat == 0 || spr->yrepeat == 0) continue; @@ -5291,12 +5292,12 @@ void polymost_scansector(int32_t sectnum) vec2d_t p2 = { 0, 0 }; - uwalltype *wal; + uwallptr_t wal; int z; - for (z=startwall,wal=(uwalltype *)&wall[z]; zpoint2]; + auto const wal2 = (uwallptr_t)&wall[wal->point2]; vec2d_t const fp1 = { double(wal->x - globalposx), double(wal->y - globalposy) }; vec2d_t const fp2 = { double(wal2->x - globalposx), double(wal2->y - globalposy) }; @@ -5551,15 +5552,16 @@ void polymost_drawrooms() { gshang = 0.f; gchang = 1.f; - ghoriz2 = (float)(ydimen >> 1) - ghoriz - ghorizcorrect; + ghoriz2 = (float)(ydimen >> 1) - (ghoriz + ghorizcorrect); } else { - float r = (float)(ydimen >> 1) - ghoriz - ghorizcorrect; + float r = (float)(ydimen >> 1) - (ghoriz + ghorizcorrect); gshang = r / Bsqrtf(r * r + ghalfx * ghalfx / (gvrcorrection * gvrcorrection)); gchang = Bsqrtf(1.f - gshang * gshang); ghoriz2 = 0.f; } + ghoriz = (float)(ydimen>>1); resizeglcheck(); @@ -5761,13 +5763,13 @@ static void polymost_drawmaskwallinternal(int32_t wallIndex) auto const wal = (uwallptr_t)&wall[wallIndex]; auto const wal2 = (uwallptr_t)&wall[wal->point2]; int32_t const sectnum = wall[wal->nextwall].nextsector; - auto const sec = (usectortype *)§or[sectnum]; + auto const sec = (usectorptr_t)§or[sectnum]; // if (wal->nextsector < 0) return; // Without MASKWALL_BAD_ACCESS fix: // wal->nextsector is -1, WGR2 SVN Lochwood Hollow (Til' Death L1) (or trueror1.map) - auto const nsec = (usectortype *)§or[wal->nextsector]; + auto const nsec = (usectorptr_t)§or[wal->nextsector]; polymost_outputGLDebugMessage(3, "polymost_drawmaskwallinternal(wallIndex:%d)", wallIndex); @@ -6005,17 +6007,18 @@ void polymost_prepareMirror(int32_t dax, int32_t day, int32_t daz, fix16_t daang ghalfy = (float)(ydimen>>1); grhalfxdown10 = 1.f/(ghalfx*1024.f); ghoriz = fix16_to_float(qglobalhoriz); + ghorizcorrect = fix16_to_float((100-polymostcenterhoriz)*divscale16(xdimenscale, viewingrange)); gvisibility = ((float)globalvisibility)*FOGSCALE; resizeglcheck(); if (r_yshearing) { gshang = 0.f; gchang = 1.f; - ghoriz2 = (float)(ydimen >> 1) - ghoriz; + ghoriz2 = (float)(ydimen >> 1) - (ghoriz+ghorizcorrect); } else { - float r = (float)(ydimen >> 1) - ghoriz; + float r = (float)(ydimen >> 1) - (ghoriz+ghorizcorrect); gshang = r / Bsqrtf(r * r + ghalfx * ghalfx / (gvrcorrection * gvrcorrection)); gchang = Bsqrtf(1.f - gshang * gshang); ghoriz2 = 0.f; @@ -6068,10 +6071,10 @@ void Polymost_prepare_loadboard(void) Bmemset(wsprinfo, 0, sizeof(wsprinfo)); } -static inline int32_t polymost_findwall(uspritetype const * const tspr, vec2_t const * const tsiz, int32_t * rd) +static inline int32_t polymost_findwall(uspriteptr_t const tspr, vec2_t const * const tsiz, int32_t * rd) { int32_t dist = 4, closest = -1; - usectortype const * const sect = (usectortype * )§or[tspr->sectnum]; + auto const sect = (usectortype * )§or[tspr->sectnum]; vec2_t n; for (bssize_t i=sect->wallptr; iwallptr + sect->wallnum; i++) @@ -6140,12 +6143,12 @@ int32_t polymost_lintersect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, void polymost_drawsprite(int32_t snum) { - uspritetype *const tspr = tspriteptr[snum]; + auto const tspr = tspriteptr[snum]; if (EDUKE32_PREDICT_FALSE(bad_tspr(tspr))) return; - const usectortype *sec; + usectorptr_t sec; int32_t spritenum = tspr->owner; @@ -6187,7 +6190,7 @@ void polymost_drawsprite(int32_t snum) drawpoly_alpha = spriteext[spritenum].alpha; drawpoly_blend = tspr->blend; - sec = (usectortype *)§or[tspr->sectnum]; + sec = (usectorptr_t)§or[tspr->sectnum]; //if ((usehightile && hicfindsubst(globalpicnum, globalpal, hictinting[globalpal].f & HICTINT_ALWAYSUSEART)) //|| (usemodels && md_tilehasmodel(globalpicnum, globalpal) >= 0)) @@ -7804,10 +7807,6 @@ void polymost_initosdfuncs(void) static osdcvardata_t cvars_polymost[] = { - { "r_animsmoothing","enable/disable model animation smoothing",(void *) &r_animsmoothing, CVAR_BOOL, 0, 1 }, - { "r_fullbrights","enable/disable fullbright textures",(void *) &r_fullbrights, CVAR_BOOL, 0, 1 }, - { "r_parallaxskyclamping","enable/disable parallaxed floor/ceiling sky texture clamping", (void *) &r_parallaxskyclamping, CVAR_BOOL, 0, 1 }, - { "r_parallaxskypanning","enable/disable parallaxed floor/ceiling panning when drawing a parallaxing sky", (void *) &r_parallaxskypanning, CVAR_BOOL, 0, 1 }, { "r_polymostDebug","Set the verbosity of Polymost GL debug messages",(void *) &r_polymostDebug, CVAR_INT, 0, 3 }, #ifdef USE_GLEXT { "r_detailmapping","enable/disable detail mapping",(void *) &r_detailmapping, CVAR_BOOL, 0, 1 }, @@ -7815,37 +7814,32 @@ void polymost_initosdfuncs(void) #endif { "r_polygonmode","debugging feature",(void *) &r_polygonmode, CVAR_INT | CVAR_NOSAVE, 0, 3 }, + { "r_animsmoothing","enable/disable model animation smoothing",(void *) &r_animsmoothing, CVAR_BOOL, 0, 1 }, + { "r_anisotropy", "changes the OpenGL texture anisotropy setting", (void *) &glanisotropy, CVAR_INT|CVAR_FUNCPTR, 0, 16 }, + { "r_fullbrights","enable/disable fullbright textures",(void *) &r_fullbrights, CVAR_BOOL, 0, 1 }, + { "r_hightile","enable/disable hightile texture rendering",(void *) &usehightile, CVAR_BOOL, 0, 1 }, + { "r_models", "enable/disable model rendering", (void *)&usemodels, CVAR_BOOL, 0, 1 }, + { "r_nofog", "enable/disable GL fog", (void *)&nofog, CVAR_BOOL, 0, 1}, + { "r_npotwallmode", "enable/disable emulation of walls with non-power-of-two height textures (Polymost, r_hightile 0)", + (void *) &r_npotwallmode, CVAR_INT | CVAR_NOSAVE, 0, 2 }, + { "r_parallaxskyclamping","enable/disable parallaxed floor/ceiling sky texture clamping", (void *) &r_parallaxskyclamping, CVAR_BOOL, 0, 1 }, + { "r_parallaxskypanning","enable/disable parallaxed floor/ceiling panning when drawing a parallaxing sky", (void *) &r_parallaxskypanning, CVAR_BOOL, 0, 1 }, + { "r_projectionhack", "enable/disable projection hack", (void *) &glprojectionhacks, CVAR_INT, 0, 2 }, + { "r_shadeinterpolate", "enable/disable shade interpolation", (void *) &r_shadeinterpolate, CVAR_BOOL, 0, 1 }, { "r_shadescale","multiplier for shading",(void *) &shadescale, CVAR_FLOAT, 0, 10 }, { "r_shadescale_unbounded","enable/disable allowance of complete blackness",(void *) &shadescale_unbounded, CVAR_BOOL, 0, 1 }, { "r_swapinterval","sets the GL swap interval (VSync)",(void *) &vsync, CVAR_INT|CVAR_FUNCPTR, -1, 1 }, - { - "r_npotwallmode", "enable/disable emulation of walls with non-power-of-two height textures (Polymost, r_hightile 0)", - (void *) &r_npotwallmode, CVAR_INT, 0, 2 - }, - { "r_anisotropy", "changes the OpenGL texture anisotropy setting", (void *) &glanisotropy, CVAR_INT|CVAR_FUNCPTR, 0, 16 }, { "r_texturemaxsize","changes the maximum OpenGL texture size limit",(void *) &gltexmaxsize, CVAR_INT | CVAR_NOSAVE, 0, 4096 }, { "r_texturemiplevel","changes the highest OpenGL mipmap level used",(void *) &gltexmiplevel, CVAR_INT, 0, 6 }, { "r_texfilter", "changes the texture filtering settings (may require restart)", (void *) &gltexfiltermode, CVAR_INT|CVAR_FUNCPTR, 0, 5 }, { "r_useindexedcolortextures", "enable/disable indexed color texture rendering", (void *) &r_useindexedcolortextures, CVAR_INT, 0, 1 }, - { "r_usenewshading", - "visibility/fog code: 0: orig. Polymost 1: 07/2011 2: linear 12/2012 3: no neg. start 03/2014 4: base constant on shade table 11/2017", - (void *) &r_usenewshading, CVAR_INT|CVAR_FUNCPTR, 0, 4 - }, - - { "r_projectionhack", "enable/disable projection hack", (void *) &glprojectionhacks, CVAR_INT, 0, 1 }, - { "r_shadeinterpolate", "enable/disable shade interpolation", (void *) &r_shadeinterpolate, CVAR_INT, 0, 1 }, - { "r_yshearing", "enable/disable y-shearing", (void*)&r_yshearing, CVAR_INT, 0, 1 }, - - -#ifdef __ANDROID__ - { "r_models","enable/disable model rendering",(void *) &usemodels, CVAR_BOOL | CVAR_NOSAVE, 0, 1 }, -#else - { "r_models","enable/disable model rendering",(void *) &usemodels, CVAR_BOOL, 0, 1 }, + { "r_usenewshading", + "visibility/fog code: 0: orig. Polymost 1: 07/2011 2: linear 12/2012 3: no neg. start 03/2014 4: base constant on shade table 11/2017", + (void*)& r_usenewshading, CVAR_INT | CVAR_FUNCPTR, 0, 4}, + { "r_yshearing", "enable/disable y-shearing", (void*) &r_yshearing, CVAR_BOOL, 0, 1 }, + { "r_flatsky", "enable/disable flat skies", (void*)& r_flatsky, CVAR_BOOL, 0, 1 }, #endif - { "r_nofog", "enable/disable GL fog", (void *)&nofog, CVAR_BOOL, 0, 1}, - { "r_hightile","enable/disable hightile texture rendering",(void *) &usehightile, CVAR_BOOL, 0, 1 }, - }; for (i=0; i= MAXARTFILES_BASE); // is it a per-map ART file? buildvfs_kfd fil; - auto kopen4loadfunc = playing_blood ? kopen4loadfrommod : kopen4load; + auto kopen4loadfunc = bloodhack == 2 ? kopen4loadfrommod : kopen4load; if ((fil = kopen4loadfunc(fn, 0)) != buildvfs_kfd_invalid) { @@ -713,7 +713,7 @@ void tileLoadData(int16_t tilenume, int32_t dasiz, char *buffer) char const *fn = artGetIndexedFileName(tfn); - auto kopen4loadfunc = playing_blood ? kopen4loadfrommod : kopen4load; + auto kopen4loadfunc = bloodhack == 2 ? kopen4loadfrommod : kopen4load; artfil = kopen4loadfunc(fn, 0); diff --git a/source/duke3d/src/events_defs.h b/source/duke3d/src/events_defs.h index a1de4328b..48e9a0e41 100644 --- a/source/duke3d/src/events_defs.h +++ b/source/duke3d/src/events_defs.h @@ -160,6 +160,8 @@ enum GameEvent_t { EVENT_RESETGOTPICS, EVENT_VALIDATESTART, EVENT_NEWGAMECUSTOM, + EVENT_INITCOMPLETE, + EVENT_CAPIR, #ifdef LUNATIC EVENT_ANIMATEALLSPRITES, #endif diff --git a/source/duke3d/src/game.cpp b/source/duke3d/src/game.cpp index 7cdec4770..0403b655a 100644 --- a/source/duke3d/src/game.cpp +++ b/source/duke3d/src/game.cpp @@ -820,12 +820,12 @@ void G_DrawRooms(int32_t playerNum, int32_t smoothRatio) #endif #ifdef POLYMER if (videoGetRenderMode() == REND_POLYMER) - polymer_setanimatesprites(G_DoSpriteAnimations, pSprite->x, pSprite->y, pSprite->z, fix16_to_int(CAMERA(q16ang)), smoothRatio); + polymer_setanimatesprites(G_DoSpriteAnimations, pSprite->x, pSprite->y, pSprite->z - ZOFFSET6, fix16_to_int(CAMERA(q16ang)), smoothRatio); #endif yax_preparedrawrooms(); renderDrawRoomsQ16(pSprite->x, pSprite->y, pSprite->z - ZOFFSET6, CAMERA(q16ang), fix16_from_int(pSprite->yvel), pSprite->sectnum); yax_drawrooms(G_DoSpriteAnimations, pSprite->sectnum, 0, smoothRatio); - G_DoSpriteAnimations(pSprite->x, pSprite->y, pSprite->z, fix16_to_int(CAMERA(q16ang)), smoothRatio); + G_DoSpriteAnimations(pSprite->x, pSprite->y, pSprite->z - ZOFFSET6, fix16_to_int(CAMERA(q16ang)), smoothRatio); renderDrawMasks(); } } @@ -6143,10 +6143,10 @@ static void G_Startup(void) if (g_modDir[0] != '/' && (cwd = buildvfs_getcwd(NULL, 0))) { buildvfs_chdir(g_modDir); - if (artLoadFiles("tiles%03d.art", MAXCACHE1DSIZE) < 0) + if (artLoadFiles("tiles%03i.art", MAXCACHE1DSIZE) < 0) { buildvfs_chdir(cwd); - if (artLoadFiles("tiles%03d.art", MAXCACHE1DSIZE) < 0) + if (artLoadFiles("tiles%03i.art", MAXCACHE1DSIZE) < 0) G_GameExit("Failed loading art."); } buildvfs_chdir(cwd); @@ -6154,7 +6154,7 @@ static void G_Startup(void) Xfree(cwd); #endif } - else if (artLoadFiles("tiles%03d.art",MAXCACHE1DSIZE) < 0) + else if (artLoadFiles("tiles%03i.art",MAXCACHE1DSIZE) < 0) G_GameExit("Failed loading art."); cacheAllSounds(); @@ -6809,6 +6809,8 @@ int app_main(int argc, char const * const * argv) // getpackets(); + VM_OnEvent(EVENT_INITCOMPLETE); + MAIN_LOOP_RESTART: totalclock = 0; ototalclock = 0; diff --git a/source/duke3d/src/gamedef.cpp b/source/duke3d/src/gamedef.cpp index 11f98c04a..b53cf358a 100644 --- a/source/duke3d/src/gamedef.cpp +++ b/source/duke3d/src/gamedef.cpp @@ -166,6 +166,8 @@ static tokenmap_t const vm_keywords[] = { "calchypotenuse", CON_CALCHYPOTENUSE }, { "cansee", CON_CANSEE }, { "canseespr", CON_CANSEESPR }, + { "capia", CON_CAPIA }, + { "capis", CON_CAPIS }, { "case", CON_CASE }, { "changespritesect", CON_CHANGESPRITESECT }, { "changespritestat", CON_CHANGESPRITESTAT }, @@ -992,6 +994,8 @@ const char *EventNames[MAXEVENTS] = "EVENT_RESETGOTPICS", "EVENT_VALIDATESTART", "EVENT_NEWGAMECUSTOM", + "EVENT_INITCOMPLETE", + "EVENT_CAPIR", #ifdef LUNATIC "EVENT_ANIMATEALLSPRITES", #endif @@ -3595,6 +3599,7 @@ DO_DEFSTATE: fallthrough__; case CON_ACTIVATECHEAT: case CON_ANGOFF: + case CON_CAPIA: case CON_CHECKACTIVATORMOTION: case CON_CHECKAVAILINVEN: case CON_CHECKAVAILWEAPON: @@ -3658,6 +3663,7 @@ DO_DEFSTATE: C_GetNextVarType(GAMEVAR_READONLY); fallthrough__; case CON_ACTORSOUND: + case CON_CAPIS: case CON_CHANGESPRITESECT: case CON_CHANGESPRITESTAT: case CON_EZSHOOT: diff --git a/source/duke3d/src/gamedef.h b/source/duke3d/src/gamedef.h index 16a519d41..2cbb160bb 100644 --- a/source/duke3d/src/gamedef.h +++ b/source/duke3d/src/gamedef.h @@ -1069,6 +1069,8 @@ enum IterationTypes_t TRANSFORM(CON_CALCHYPOTENUSE) DELIMITER \ TRANSFORM(CON_CANSEE) DELIMITER \ TRANSFORM(CON_CANSEESPR) DELIMITER \ + TRANSFORM(CON_CAPIA) DELIMITER \ + TRANSFORM(CON_CAPIS) DELIMITER \ TRANSFORM(CON_CHANGESPRITESECT) DELIMITER \ TRANSFORM(CON_CHANGESPRITESTAT) DELIMITER \ TRANSFORM(CON_CHECKACTIVATORMOTION) DELIMITER \ diff --git a/source/duke3d/src/gameexec.cpp b/source/duke3d/src/gameexec.cpp index b10791a85..3d1193459 100644 --- a/source/duke3d/src/gameexec.cpp +++ b/source/duke3d/src/gameexec.cpp @@ -4834,6 +4834,29 @@ badindex: dispatch(); } + vInstruction(CON_CAPIA): + { + insptr++; + int const nQuote = Gv_GetVar(*insptr++); + + VM_ASSERT((unsigned)nQuote < MAXQUOTES && apStrings[nQuote], "invalid quote %d\n", nQuote); + + //communityapiUnlockAchievement(apStrings[nQuote]); + dispatch(); + } + + vInstruction(CON_CAPIS): + { + insptr++; + int const nQuote = Gv_GetVar(*insptr++); + int const value = Gv_GetVar(*insptr++); + + VM_ASSERT((unsigned)nQuote < MAXQUOTES && apStrings[nQuote], "invalid quote %d\n", nQuote); + + //communityapiSetStat(apStrings[nQuote], value); + dispatch(); + } + vInstruction(CON_SPAWN): insptr++; diff --git a/source/duke3d/src/menus.cpp b/source/duke3d/src/menus.cpp index f6786822a..6b3ae98a2 100644 --- a/source/duke3d/src/menus.cpp +++ b/source/duke3d/src/menus.cpp @@ -307,8 +307,8 @@ MAKE_SPACER( Space8, 8<<16 ); // colcorr, redslide static MenuEntry_t ME_Space2_Redfont = MAKE_MENUENTRY( NULL, &MF_Redfont, &MEF_Null, &MEO_Space2, Spacer ); static MenuEntry_t ME_Space4_Bluefont = MAKE_MENUENTRY( NULL, &MF_Bluefont, &MEF_Null, &MEO_Space4, Spacer ); -#ifndef EDUKE32_SIMPLE_MENU static MenuEntry_t ME_Space4_Redfont = MAKE_MENUENTRY( NULL, &MF_Redfont, &MEF_Null, &MEO_Space4, Spacer ); +#ifndef EDUKE32_SIMPLE_MENU static MenuEntry_t ME_Space8_Bluefont = MAKE_MENUENTRY( NULL, &MF_Bluefont, &MEF_Null, &MEO_Space8, Spacer ); #endif static MenuEntry_t ME_Space6_Redfont = MAKE_MENUENTRY( NULL, &MF_Redfont, &MEF_Null, &MEO_Space6, Spacer ); @@ -751,7 +751,7 @@ static MenuEntry_t *MEL_VIDEOSETUP[] = { &ME_VIDEOSETUP_VSYNC, &ME_VIDEOSETUP_FRAMELIMIT, &ME_VIDEOSETUP_FRAMELIMITOFFSET, - &ME_Space6_Redfont, + &ME_Space4_Redfont, &ME_VIDEOSETUP_APPLY, }; static MenuEntry_t *MEL_DISPLAYSETUP[] = { diff --git a/source/duke3d/src/sounds.cpp b/source/duke3d/src/sounds.cpp index 4bd946e9c..b849965ea 100644 --- a/source/duke3d/src/sounds.cpp +++ b/source/duke3d/src/sounds.cpp @@ -972,12 +972,12 @@ void S_Update(void) // when playing back a new sound needs an existing sound to be stopped first void S_Callback(intptr_t num) { - if (num == MUSIC_ID) + if ((int32_t)num == MUSIC_ID) return; mutex_lock(&m_callback); unative_t const ldnum = dnum; - dq[ldnum & (DQSIZE - 1)] = num; + dq[ldnum & (DQSIZE - 1)] = (uint32_t)num; dnum++; mutex_unlock(&m_callback); } diff --git a/source/rr/src/actors.cpp b/source/rr/src/actors.cpp index 8a518e83e..131c1cf7e 100644 --- a/source/rr/src/actors.cpp +++ b/source/rr/src/actors.cpp @@ -3503,8 +3503,7 @@ default_case: A_SetSprite(newSprite, CLIPMASK0); } - actor[sectSprite].lasttransport = ((int32_t)totalclock & UINT8_MAX); - + actor[sectSprite].lasttransport = ((int32_t) totalclock & UINT8_MAX); if (sectLotag == ST_1_ABOVE_WATER || sectLotag == ST_2_UNDERWATER) { diff --git a/source/rr/src/config.cpp b/source/rr/src/config.cpp index 95421a345..683ea75a0 100644 --- a/source/rr/src/config.cpp +++ b/source/rr/src/config.cpp @@ -630,20 +630,25 @@ int32_t CONFIG_ReadSetup(void) if (ud.config.scripthandle < 0) { - if (buildvfs_exists(g_setupFileName)) // JBF 20031211 - ud.config.scripthandle = SCRIPT_Load(g_setupFileName); + if (buildvfs_exists(g_setupFileName)) // JBF 20031211 + ud.config.scripthandle = SCRIPT_Load(g_setupFileName); #if !defined(EDUKE32_TOUCH_DEVICES) - else if (buildvfs_exists(SETUPFILENAME)) - { - int const i = wm_ynbox("Import Configuration Settings", - "The configuration file \"%s\" was not found. " - "Import configuration data from \"%s\"?", - g_setupFileName, SETUPFILENAME); - if (i) - ud.config.scripthandle = SCRIPT_Load(SETUPFILENAME); - } + else if (buildvfs_exists(SETUPFILENAME)) + { + int32_t i; + i=wm_ynbox("Import Configuration Settings", "The configuration file \"%s\" was not found. " + "Import configuration data from \"%s\"?", g_setupFileName, SETUPFILENAME); + if (i) ud.config.scripthandle = SCRIPT_Load(SETUPFILENAME); + } + else if (buildvfs_exists("duke3d.cfg")) + { + int32_t i; + i=wm_ynbox("Import Configuration Settings", "The configuration file \"%s\" was not found. " + "Import configuration data from \"duke3d.cfg\"?", g_setupFileName); + if (i) ud.config.scripthandle = SCRIPT_Load("duke3d.cfg"); + } #endif - } + } pathsearchmode = 0; diff --git a/source/rr/src/demo.cpp b/source/rr/src/demo.cpp index 613f3e823..6bbf2f51e 100644 --- a/source/rr/src/demo.cpp +++ b/source/rr/src/demo.cpp @@ -631,8 +631,10 @@ RECHECK: renderFlushPerms(); +#ifdef PLAYDEMOLOOP // Todo: Make a CVar. if (!g_netServer && ud.multimode < 2) - foundemo = 0;// G_OpenDemoRead(g_whichDemo); + foundemo = G_OpenDemoRead(g_whichDemo); +#endif if (foundemo == 0) { @@ -988,7 +990,7 @@ nextdemo_nomenu: } else { - j = calc_smoothratio((int32_t)totalclock, (int32_t)ototalclock); + j = calc_smoothratio(totalclock, ototalclock); if (g_demo_paused && g_demo_rewind) j = 65536-j; diff --git a/source/rr/src/game.cpp b/source/rr/src/game.cpp index 48129f8a0..b4834f6f1 100644 --- a/source/rr/src/game.cpp +++ b/source/rr/src/game.cpp @@ -979,7 +979,7 @@ void G_DrawRooms(int32_t playerNum, int32_t smoothRatio) if (ud.pause_on || pPlayer->on_crane > -1) smoothRatio = 65536; else - smoothRatio = calc_smoothratio((int32_t)totalclock, (int32_t)ototalclock); + smoothRatio = calc_smoothratio(totalclock, ototalclock); if (RRRA && g_fogType) pPlayer->visibility = ud.const_visibility; @@ -7452,6 +7452,8 @@ static void G_Startup(void) G_CompileScripts(); + blooddemohack = 1; + if (engineInit()) G_FatalEngineError(); diff --git a/source/rr/src/gameexec.cpp b/source/rr/src/gameexec.cpp index 08f786e66..7fd1a7f39 100644 --- a/source/rr/src/gameexec.cpp +++ b/source/rr/src/gameexec.cpp @@ -1149,7 +1149,6 @@ void Screen_Play(void) videoNextPage(); I_ClearAllInput(); - videoNextPage(); } while (running); } diff --git a/source/rr/src/menus.cpp b/source/rr/src/menus.cpp index a4adea4d2..85442d6f3 100644 --- a/source/rr/src/menus.cpp +++ b/source/rr/src/menus.cpp @@ -7638,14 +7638,14 @@ void M_DisplayMenus(void) m_menuchange_watchpoint++; #endif - if ((int32_t)totalclock < m_animation.start) + if (totalclock < m_animation.start) { m_animation.start = 0; m_animation.length = 0; } // Determine animation values. - if ((int32_t)totalclock < m_animation.start + m_animation.length) + if (totalclock < m_animation.start + m_animation.length) { const int32_t screenwidth = scale(240<<16, xdim, ydim); @@ -7659,7 +7659,7 @@ void M_DisplayMenus(void) } // Display the menu, with a transition animation if applicable. - if ((int32_t)totalclock < m_animation.start + m_animation.length) + if (totalclock < m_animation.start + m_animation.length) { Menu_Run(m_animation.previous, previousOrigin); Menu_Run(m_animation.current, origin); diff --git a/source/rr/src/net.cpp b/source/rr/src/net.cpp index a4ce6c69d..37d6a0e52 100644 --- a/source/rr/src/net.cpp +++ b/source/rr/src/net.cpp @@ -88,7 +88,7 @@ void Net_SyncPlayer(ENetEvent *event) event->peer->data = (void *)(intptr_t)i; - g_player[i].netsynctime = (int32_t)totalclock; + //g_player[i].netsynctime = totalclock; g_player[i].playerquitflag = 1; //g_player[i].revision = g_netMapRevision; @@ -2178,7 +2178,7 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) if ((g_player[other].movefifoend&(TIMERUPDATESIZ-1)) == 0) for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) - { + { if (g_player[i].playerquitflag == 0) continue; if (i == myconnectindex) otherminlag = (int)((signed char)packbuf[j]); @@ -2192,7 +2192,7 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) for(TRAVERSE_CONNECT(i)) j += g_player[i].playerquitflag+g_player[i].playerquitflag; for(TRAVERSE_CONNECT(i)) - { + { if (g_player[i].playerquitflag == 0) continue; l = packbuf[k]+(int)(packbuf[k+1]<<8); @@ -2260,7 +2260,7 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) movefifosendplc += g_movesPerPacket; - break; + break; case PACKET_TYPE_SLAVE_TO_MASTER: //[1] (receive slave sync buffer) j = 3; k = packbuf[1] + (int)(packbuf[2]<<8); @@ -2272,13 +2272,13 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) if (k&1) nsyn[other].fvel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2; if (k&2) nsyn[other].svel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2; if (k&4) - { + { nsyn[other].q16avel = (fix16_t)packbuf[j]; nsyn[other].q16avel += (fix16_t)packbuf[j + 1] << 8; nsyn[other].q16avel += (fix16_t)packbuf[j + 2] << 16; nsyn[other].q16avel += (fix16_t)packbuf[j + 3] << 24; j += 4; - } + } if (k&8) nsyn[other].bits = ((nsyn[other].bits&0xffffff00)|((int)packbuf[j++])); if (k&16) nsyn[other].bits = ((nsyn[other].bits&0xffff00ff)|((int)packbuf[j++])<<8); if (k&32) nsyn[other].bits = ((nsyn[other].bits&0xff00ffff)|((int)packbuf[j++])<<16); @@ -2311,7 +2311,7 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) g_player[other].movefifoend++; } - break; + break; case PACKET_TYPE_BROADCAST: g_player[other].movefifoend = movefifoplc = movefifosendplc = predictfifoplc = 0; @@ -2326,7 +2326,7 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) if (i == myconnectindex) otherminlag = (int)((signed char)packbuf[j]); j++; - } + } osyn = (input_t *)&inputfifo[(g_player[other].movefifoend-1)&(MOVEFIFOSIZ-1)][0]; nsyn = (input_t *)&inputfifo[(g_player[other].movefifoend)&(MOVEFIFOSIZ-1)][0]; @@ -2338,7 +2338,7 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) if (k&1) nsyn[other].fvel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2; if (k&2) nsyn[other].svel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2; if (k&4) - { + { nsyn[other].q16avel = (fix16_t)packbuf[j]; nsyn[other].q16avel += (fix16_t)packbuf[j + 1] << 8; nsyn[other].q16avel += (fix16_t)packbuf[j + 2] << 16; @@ -2350,7 +2350,7 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) if (k&32) nsyn[other].bits = ((nsyn[other].bits&0xff00ffff)|((int)packbuf[j++])<<16); if (k&64) nsyn[other].bits = ((nsyn[other].bits&0x00ffffff)|((int)packbuf[j++])<<24); if (k&128) - { + { nsyn[other].q16horz = (fix16_t)packbuf[j]; nsyn[other].q16horz += (fix16_t)packbuf[j + 1] << 8; nsyn[other].q16horz += (fix16_t)packbuf[j + 2] << 16; @@ -2366,10 +2366,10 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) g_player[other].movefifoend++; for (i=g_movesPerPacket-1;i>=1;i--) - { + { copybufbyte(&nsyn[other],&inputfifo[g_player[other].movefifoend&(MOVEFIFOSIZ-1)][other],sizeof(input_t)); g_player[other].movefifoend++; - } + } /* while (j < packbufleng) @@ -2383,7 +2383,7 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) if (j > packbufleng) initprintf("INVALID GAME PACKET!!! (packet %d, %d too many bytes (%d %d))\n",packbuf[0],j-packbufleng,packbufleng,k); - break; + break; case PACKET_TYPE_NULL_PACKET: break; @@ -2427,7 +2427,7 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) pus = NUMPAGES; pub = NUMPAGES; - break; + break; case PACKET_TYPE_NEW_GAME: //Slaves in M/S mode only send to master @@ -2500,14 +2500,14 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) { initprintf("Player has version %d, expecting %d\n",packbuf[2],(char)atoi(s_buildDate)); G_GameExit("You cannot play with different versions of EDuke32!"); - } + } if (packbuf[3] != (char)BYTEVERSION) { initprintf("Player has version %d, expecting %d (%d, %d, %d)\n",packbuf[3],BYTEVERSION, NETVERSION, PLUTOPAK, VOLUMEONE); G_GameExit("You cannot play Duke with different versions!"); - } + } if (packbuf[4] > g_numSyncBytes) - { + { initprintf("Sync debugging enabled\n"); g_numSyncBytes = packbuf[4]; } @@ -2604,7 +2604,7 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) case PACKET_TYPE_MENU_LEVEL_QUIT: //slaves in M/S mode only send to master if (myconnectindex == connecthead) - { + { //Master re-transmits message to all others for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) if (i != other) @@ -2629,7 +2629,7 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) boardfilename[packbufleng-1] = 0; Bcorrectfilename(boardfilename,0); if (boardfilename[0] != 0) - { + { if ((i = kopen4loadfrommod(boardfilename,0)) < 0) { Bmemset(boardfilename,0,sizeof(boardfilename)); @@ -2641,7 +2641,7 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) if (ud.m_level_number == 7 && ud.m_volume_number == 0 && boardfilename[0] == 0) ud.m_level_number = 0; - break; + break; case PACKET_TYPE_MAP_VOTE: case PACKET_TYPE_MAP_VOTE_INITIATE: @@ -2653,7 +2653,7 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) if (i != other) Net_SendPacket(i,packbuf,packbufleng); - } + } switch (packbuf[0]) { @@ -2665,7 +2665,7 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) Bsprintf(tempbuf,"Confirmed vote from %s",g_player[packbuf[1]].user_name); G_AddUserQuote(tempbuf); } - break; + break; case PACKET_TYPE_MAP_VOTE_INITIATE: // call map vote /* if (g_networkBroadcastMode == 0 && packbuf[1] == connecthead) @@ -2706,11 +2706,11 @@ void Net_ParsePacket(uint8_t *packbuf, int packbufleng) { g_player[i].vote = 0; g_player[i].gotvote = 0; - } + } G_AddUserQuote(tempbuf); - } + } break; - } + } break; //case PACKET_TYPE_LOAD_GAME: @@ -3063,12 +3063,12 @@ void Net_ParseClientPacket(ENetEvent *event) break; default: { - uint8_t *pbuf = event->packet->data; - int32_t packbufleng = event->packet->dataLength; - int16_t j; - int32_t other = pbuf[--packbufleng]; - switch (pbuf[0]) - { + uint8_t *pbuf = event->packet->data; + int32_t packbufleng = event->packet->dataLength; + int16_t j; + int32_t other = pbuf[--packbufleng]; + switch (pbuf[0]) + { //case PACKET_SLAVE_TO_MASTER: //[1] (receive slave sync buffer) // Net_ReceiveClientUpdate(event); // break; @@ -3105,14 +3105,14 @@ void Net_ParseClientPacket(ENetEvent *event) // g_player[other].pingcnt++; // break; - case PACKET_AUTH: - Net_ReceiveChallenge(pbuf, packbufleng, event); - break; + case PACKET_AUTH: + Net_ReceiveChallenge(pbuf, packbufleng, event); + break; - default: - Net_ParsePacketCommon(pbuf, packbufleng, 0); - break; - } + default: + Net_ParsePacketCommon(pbuf, packbufleng, 0); + break; + } break; } } @@ -3168,7 +3168,7 @@ void Net_ParseServerPacket(ENetEvent *event) case PACKET_PLAYER_DISCONNECTED: //if ((g_player[myconnectindex].ps->gm & MODE_GAME)) - P_RemovePlayer(pbuf[1]); + P_RemovePlayer(pbuf[1]); numplayers = pbuf[2]; ud.multimode = pbuf[3]; g_mostConcurrentPlayers = pbuf[4]; diff --git a/source/rr/src/osdcmds.cpp b/source/rr/src/osdcmds.cpp index b22c6db32..ef56ce64c 100644 --- a/source/rr/src/osdcmds.cpp +++ b/source/rr/src/osdcmds.cpp @@ -619,7 +619,7 @@ static int osdcmd_cmenu(osdcmdptr_t parm) if ((g_player[myconnectindex].ps->gm & MODE_MENU) != MODE_MENU) Menu_Open(myconnectindex); - Menu_Change(Batol(parm->parms[0])); + Menu_Change(Batol(parm->parms[0])); return OSDCMD_OK; } @@ -769,7 +769,7 @@ static int osdcmd_button(osdcmdptr_t parm) // if (g_player[myconnectindex].ps->gm == MODE_GAME) // only trigger these if in game CONTROL_ButtonFlags[CONFIG_FunctionNameToNum(p)] = 1; // FIXME - return OSDCMD_OK; + return OSDCMD_OK; } const char *const ConsoleButtons[] = @@ -887,37 +887,37 @@ static int osdcmd_bind(osdcmdptr_t parm) CONTROL_BindKey(sctokeylut[i].sc, tempbuf, repeat, sctokeylut[i].key); - char *cp = tempbuf; + char *cp = tempbuf; - // Populate the keyboard config menu based on the bind. - // Take care of processing one-to-many bindings properly, too. + // Populate the keyboard config menu based on the bind. + // Take care of processing one-to-many bindings properly, too. static char const s_gamefunc_[] = "gamefunc_"; int constexpr strlen_gamefunc_ = ARRAY_SIZE(s_gamefunc_) - 1; while ((cp = Bstrstr(cp, s_gamefunc_))) - { + { cp += strlen_gamefunc_; char *semi = Bstrchr(cp, ';'); - if (semi) - *semi = 0; + if (semi) + *semi = 0; - j = CONFIG_FunctionNameToNum(cp); + j = CONFIG_FunctionNameToNum(cp); - if (semi) - cp = semi+1; + if (semi) + cp = semi+1; - if (j != -1) - { - ud.config.KeyboardKeys[j][1] = ud.config.KeyboardKeys[j][0]; + if (j != -1) + { + ud.config.KeyboardKeys[j][1] = ud.config.KeyboardKeys[j][0]; ud.config.KeyboardKeys[j][0] = sctokeylut[i].sc; // CONTROL_MapKey(j, sctokeylut[i].sc, ud.config.KeyboardKeys[j][0]); - if (j == gamefunc_Show_Console) + if (j == gamefunc_Show_Console) OSD_CaptureKey(sctokeylut[i].sc); - } } + } if (!OSD_ParsingScript()) OSD_Printf("%s\n",parm->raw); @@ -963,10 +963,10 @@ static int osdcmd_unbind(osdcmdptr_t parm) { if (!Bstrcasecmp(parm->parms[0], ConsoleButtons[i])) { - CONTROL_FreeMouseBind(i); + CONTROL_FreeMouseBind(i); OSD_Printf("unbound %s\n", ConsoleButtons[i]); - return OSDCMD_OK; - } + return OSDCMD_OK; + } } return OSDCMD_SHOWHELP; @@ -1507,12 +1507,12 @@ int32_t registerosdcommands(void) { switch (cv.flags & (CVAR_FUNCPTR|CVAR_MULTI)) { - case CVAR_FUNCPTR: + case CVAR_FUNCPTR: OSD_RegisterCvar(&cv, osdcmd_cvar_set_game); break; - case CVAR_MULTI: - case CVAR_FUNCPTR|CVAR_MULTI: + case CVAR_MULTI: + case CVAR_FUNCPTR|CVAR_MULTI: OSD_RegisterCvar(&cv, osdcmd_cvar_set_multi); break; - default: + default: OSD_RegisterCvar(&cv, osdcmd_cvar_set); break; } } diff --git a/source/rr/src/player.cpp b/source/rr/src/player.cpp index b76dfd418..08601d2f3 100644 --- a/source/rr/src/player.cpp +++ b/source/rr/src/player.cpp @@ -2736,12 +2736,13 @@ enddisplayweapon: int32_t g_myAimMode = 0, g_myAimStat = 0, g_oldAimStat = 0; int32_t mouseyaxismode = -1; -void P_GetInput(int const playerNum) + +void P_GetInput(int playerNum) { auto const pPlayer = g_player[playerNum].ps; ControlInfo info; - if ((pPlayer->gm & (MODE_MENU | MODE_TYPE)) || (ud.pause_on && !KB_KeyPressed(sc_Pause))) + if ((pPlayer->gm & (MODE_MENU|MODE_TYPE)) || (ud.pause_on && !KB_KeyPressed(sc_Pause))) { if (!(pPlayer->gm&MODE_MENU)) CONTROL_GetInput(&info); @@ -2855,7 +2856,7 @@ void P_GetInput(int const playerNum) input.q16avel += fix16_from_int((turnHeldTime >= TURBOTURNTIME) ? (turnAmount << 1) : (PREAMBLETURN << 1)); } else - turnHeldTime = 0; + turnHeldTime=0; } if (BUTTON(gamefunc_Strafe_Left) && !(pPlayer->movement_lock & 4)) @@ -3018,11 +3019,11 @@ void P_GetInput(int const playerNum) ud.folfvel = input.fvel; ud.folavel = fix16_to_int(input.q16avel); - localInput.fvel = 0; - localInput.svel = 0; + localInput.fvel = 0; + localInput.svel = 0; - localInput.q16avel = 0; - localInput.q16horz = 0; + localInput.q16avel = 0; + localInput.q16horz = 0; return; } @@ -4008,7 +4009,7 @@ static int32_t P_DoCounters(int playerNum) } A_PlaySound(soundId, pPlayer->i); } - else if ((int32_t)totalclock > 1024) + else if (totalclock > 1024) if (playerNum == screenpeek || GTFLAGS(GAMETYPE_COOPSOUND)) { if (rand()&1) diff --git a/source/rr/src/premap.cpp b/source/rr/src/premap.cpp index a028c4930..bf4c09736 100644 --- a/source/rr/src/premap.cpp +++ b/source/rr/src/premap.cpp @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "menus.h" #include "demo.h" #include "savegame.h" +#include "cmdline.h" static int32_t g_whichPalForPlayer = 9; @@ -687,7 +688,7 @@ void G_CacheMapData(void) Bmemset(gotpic, 0, sizeof(gotpic)); - endtime = timerGetTicks(); + endtime = timerGetTicks(); OSD_Printf("Cache time: %dms\n", endtime-starttime); } @@ -2177,7 +2178,7 @@ static inline void clearfrags(void) void G_ResetTimers(uint8_t keepgtics) { - ototalclock = totalclock = g_cloudClock = lockclock = 0; + totalclock = g_cloudClock = ototalclock = lockclock = 0; ready2send = 1; g_levelTextTime = 85; diff --git a/source/rr/src/screens.cpp b/source/rr/src/screens.cpp index 7615ce190..6167119b2 100644 --- a/source/rr/src/screens.cpp +++ b/source/rr/src/screens.cpp @@ -290,10 +290,10 @@ static inline void G_MoveClouds(void) { int32_t i; - if ((int32_t)totalclock <= g_cloudClock && (int32_t)totalclock >= (g_cloudClock - 7)) + if (totalclock <= g_cloudClock && totalclock >= (g_cloudClock-7)) return; - g_cloudClock = (int32_t)totalclock + 6; + g_cloudClock = totalclock+6; g_cloudX += sintable[(fix16_to_int(g_player[screenpeek].ps->q16ang)+512)&2047]>>9; g_cloudY += sintable[fix16_to_int(g_player[screenpeek].ps->q16ang)&2047]>>9; @@ -1062,7 +1062,7 @@ void G_DisplayRest(int32_t smoothratio) if (ud.overhead_on > 0) { // smoothratio = min(max(smoothratio,0),65536); - smoothratio = calc_smoothratio((int32_t)totalclock, (int32_t)ototalclock); + smoothratio = calc_smoothratio(totalclock, ototalclock); G_DoInterpolations(smoothratio); if (ud.scrollmode == 0) @@ -2420,7 +2420,7 @@ void G_BonusScreen(int32_t bonusonly) break; } } - else if ((int32_t)totalclock > (10240+120L)) break; + else if (totalclock > (10240+120L)) break; else { switch (((int32_t) totalclock>>5)&3) @@ -3010,7 +3010,7 @@ void G_BonusScreenRRRA(int32_t bonusonly) break; } } - else if ((int32_t)totalclock > (10240+120L)) break; + else if (totalclock > (10240+120L)) break; else { switch (((int32_t) totalclock>>5)&3)