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)