- Custom Dude updates and refactor

- Player Control updates
- Minor modern types updates
- There was removed GDX prefix for all modern stuff

# Conflicts:
#	source/blood/src/aiunicult.cpp
#	source/blood/src/aiunicult.h
#	source/blood/src/mapedit.cpp
#	source/blood/src/player.h
#	source/blood/src/sfx.h
This commit is contained in:
Grind Core 2019-11-24 23:53:51 +03:00 committed by Christoph Oelckers
parent 6e3bd75b1a
commit 0dbf3bbb1e
23 changed files with 1185 additions and 825 deletions

View file

@ -2737,7 +2737,7 @@ void actInit(bool bSaveLoad) {
case kDudeModernCustom: case kDudeModernCustom:
case kDudeModernCustomBurning: case kDudeModernCustomBurning:
pSprite->cstat |= 4096 + CSTAT_SPRITE_BLOCK_HITSCAN + CSTAT_SPRITE_BLOCK; pSprite->cstat |= 4096 + CSTAT_SPRITE_BLOCK_HITSCAN + CSTAT_SPRITE_BLOCK;
seqStartId = getSeqStartId(pXSprite); // by NoOne: Custom Dude stores it's SEQ in data2 seqStartId = genDudeSeqStartId(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->sysData1 = pXSprite->data3; // by NoOne move sndStartId to sysData1, because data3 used by the game;
pXSprite->data3 = 0; pXSprite->data3 = 0;
break; break;
@ -3127,10 +3127,10 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
if ((gSysRes.Lookup(pXSprite->data2 + 15, "SEQ") || gSysRes.Lookup(pXSprite->data2 + 16, "SEQ")) && pXSprite->medium == kMediumNormal) { if ((gSysRes.Lookup(pXSprite->data2 + 15, "SEQ") || gSysRes.Lookup(pXSprite->data2 + 16, "SEQ")) && pXSprite->medium == kMediumNormal) {
if (gSysRes.Lookup(pXSprite->data2 + 3, "SEQ")) { if (gSysRes.Lookup(pXSprite->data2 + 3, "SEQ")) {
pSprite->type = kDudeModernCustomBurning; pSprite->type = kDudeModernCustomBurning;
if (pXSprite->data2 == kDefaultAnimationBase) // don't inherit palette for burning if using default animation if (pXSprite->data2 == kGenDudeDefaultSeq) // don't inherit palette for burning if using default animation
pSprite->pal = 0; pSprite->pal = 0;
aiNewState(pSprite, pXSprite, &GDXGenDudeBurnGoto); aiGenDudeNewState(pSprite, &genDudeBurnGoto);
actHealDude(pXSprite, dudeInfo[55].startHealth, dudeInfo[55].startHealth); actHealDude(pXSprite, dudeInfo[55].startHealth, dudeInfo[55].startHealth);
if (pXSprite->burnTime <= 0) pXSprite->burnTime = 1200; if (pXSprite->burnTime <= 0) pXSprite->burnTime = 1200;
gDudeExtra[pSprite->extra].at0 = (int)gFrameClock + 360; gDudeExtra[pSprite->extra].at0 = (int)gFrameClock + 360;
@ -3162,7 +3162,7 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
int seqId = pXSprite->data2 + 18; int seqId = pXSprite->data2 + 18;
if (!gSysRes.Lookup(seqId, "SEQ")) { if (!gSysRes.Lookup(seqId, "SEQ")) {
seqKill(3, nXSprite); seqKill(3, nXSprite);
sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndTransforming); playGenDudeSound(pSprite, kGenDudeSndTransforming);
spritetype* pEffect = gFX.fxSpawn((FX_ID)52, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, pSprite->ang); spritetype* pEffect = gFX.fxSpawn((FX_ID)52, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, pSprite->ang);
if (pEffect != NULL) { if (pEffect != NULL) {
pEffect->cstat = CSTAT_SPRITE_ALIGNMENT_FACING; pEffect->cstat = CSTAT_SPRITE_ALIGNMENT_FACING;
@ -3187,7 +3187,10 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
return; return;
} }
seqSpawn(seqId, 3, nXSprite, -1); seqSpawn(seqId, 3, nXSprite, -1);
sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndTransforming); playGenDudeSound(pSprite, kGenDudeSndTransforming);
pXSprite->sysData1 = kGenDudeTransformStatus; // in transform
return; return;
} }
break; break;
@ -3287,7 +3290,7 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
switch (pSprite->type) { switch (pSprite->type) {
case kDudeModernCustom: case kDudeModernCustom:
case kDudeModernCustomBurning: case kDudeModernCustomBurning:
sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndDeathExplode); playGenDudeSound(pSprite, kGenDudeSndDeathExplode);
break; break;
case kDudeCultistTommy: case kDudeCultistTommy:
case kDudeCultistShotgun: case kDudeCultistShotgun:
@ -3406,15 +3409,15 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
seqSpawn(dudeInfo[nType].seqStartID+15, 3, nXSprite, nDudeToGibClient2); seqSpawn(dudeInfo[nType].seqStartID+15, 3, nXSprite, nDudeToGibClient2);
break; break;
case kDudeModernCustom: case kDudeModernCustom:
sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndDeathNormal); playGenDudeSound(pSprite, kGenDudeSndDeathNormal);
if (nSeq == 3) { if (nSeq == 3) {
bool seq15 = gSysRes.Lookup(pXSprite->data2 + 15, "SEQ"); bool seq16 = gSysRes.Lookup(pXSprite->data2 + 16, "SEQ"); GENDUDEEXTRA* pExtra = genDudeExtra(pSprite);
if (seq15 && seq16) seqSpawn((15 + Random(2)) + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); if (pExtra->availDeaths[kDmgBurn] == 3) seqSpawn((15 + Random(2)) + pXSprite->data2, 3, nXSprite, nDudeToGibClient2);
else if (seq16) seqSpawn(16 + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); else if (pExtra->availDeaths[kDmgBurn] == 2) seqSpawn(16 + pXSprite->data2, 3, nXSprite, nDudeToGibClient2);
else if (seq15) seqSpawn(15 + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); else if (pExtra->availDeaths[kDmgBurn] == 1) seqSpawn(15 + pXSprite->data2, 3, nXSprite, nDudeToGibClient2);
else if (gSysRes.Lookup(pXSprite->data2 + nSeq, "SEQ")) seqSpawn(nSeq + 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 seqSpawn(1 + pXSprite->data2, 3, nXSprite, nDudeToGibClient2);
} else { } else {
seqSpawn(nSeq + pXSprite->data2, 3, nXSprite, nDudeToGibClient1); seqSpawn(nSeq + pXSprite->data2, 3, nXSprite, nDudeToGibClient1);
@ -3423,9 +3426,8 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
pXSprite->txID = 0; // to avoid second trigger. pXSprite->txID = 0; // to avoid second trigger.
break; break;
case kDudeModernCustomBurning: case kDudeModernCustomBurning: {
{ playGenDudeSound(pSprite, kGenDudeSndDeathExplode);
sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndDeathExplode);
damageType = DAMAGE_TYPE_3; damageType = DAMAGE_TYPE_3;
if (Chance(0x4000)) { if (Chance(0x4000)) {
@ -3436,14 +3438,11 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
GibSprite(pSprite, GIBTYPE_7, &gibPos, &gibVel); GibSprite(pSprite, GIBTYPE_7, &gibPos, &gibVel);
} }
int seqId = pXSprite->data2; GENDUDEEXTRA* pExtra = genDudeExtra(pSprite);
bool seq15 = gSysRes.Lookup(pXSprite->data2 + 15, "SEQ"); bool seq16 = gSysRes.Lookup(pXSprite->data2 + 16, "SEQ"); if (pExtra->availDeaths[kDmgBurn] == 3) seqSpawn((15 + Random(2)) + pXSprite->data2, 3, nXSprite, nDudeToGibClient1);
else if (pExtra->availDeaths[kDmgBurn] == 2) seqSpawn(16 + pXSprite->data2, 3, nXSprite, nDudeToGibClient1);
if (seq15 && seq16) seqId += (15 + Random(2)); else if (pExtra->availDeaths[kDmgBurn] == 1) seqSpawn(15 + pXSprite->data2, 3, nXSprite, nDudeToGibClient1);
else if (seq16) seqId += 16; else seqSpawn(1 + pXSprite->data2, 3, nXSprite, nDudeToGibClient1);
else seqId += 15;
seqSpawn(seqId, 3, nXSprite, nDudeToGibClient1);
break; break;
} }
case kDudeBurningZombieAxe: case kDudeBurningZombieAxe:
@ -3570,30 +3569,38 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
sfxPlay3DSound(pSprite, 2103+Random(2), -1, 0); sfxPlay3DSound(pSprite, 2103+Random(2), -1, 0);
seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1); seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1);
break; break;
case kDudePodGreen:
case kDudeTentacleGreen:
case kDudePodFire:
case kDudeTentacleFire:
if ((pSprite->cstat & CSTAT_SPRITE_YFLIP)) pSprite->cstat &= ~CSTAT_SPRITE_YFLIP;
switch (pSprite->type) {
case kDudePodGreen: case kDudePodGreen:
if (Chance(0x4000) && nSeq == 3) if (Chance(0x4000) && nSeq == 3)
sfxPlay3DSound(pSprite, 2205, -1, 0); sfxPlay3DSound(pSprite, 2205, -1, 0);
else else
sfxPlay3DSound(pSprite, 2203+Random(2), -1, 0); sfxPlay3DSound(pSprite, 2203 + Random(2), -1, 0);
seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1); seqSpawn(dudeInfo[nType].seqStartID + nSeq, 3, nXSprite, -1);
break; break;
case kDudeTentacleGreen: case kDudeTentacleGreen:
if (damage == 5) if (damage == 5)
sfxPlay3DSound(pSprite, 2471, -1, 0); sfxPlay3DSound(pSprite, 2471, -1, 0);
else else
sfxPlay3DSound(pSprite, 2472, -1, 0); sfxPlay3DSound(pSprite, 2472, -1, 0);
seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1); seqSpawn(dudeInfo[nType].seqStartID + nSeq, 3, nXSprite, -1);
break; break;
case kDudePodFire: case kDudePodFire:
if (damage == 5) if (damage == 5)
sfxPlay3DSound(pSprite, 2451, -1, 0); sfxPlay3DSound(pSprite, 2451, -1, 0);
else else
sfxPlay3DSound(pSprite, 2452, -1, 0); sfxPlay3DSound(pSprite, 2452, -1, 0);
seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1); seqSpawn(dudeInfo[nType].seqStartID + nSeq, 3, nXSprite, -1);
break; break;
case kDudeTentacleFire: case kDudeTentacleFire:
sfxPlay3DSound(pSprite, 2501, -1, 0); sfxPlay3DSound(pSprite, 2501, -1, 0);
seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1); seqSpawn(dudeInfo[nType].seqStartID + nSeq, 3, nXSprite, -1);
break;
}
break; break;
case kDudePodMother: case kDudePodMother:
if (Chance(0x4000) && nSeq == 3) if (Chance(0x4000) && nSeq == 3)
@ -4717,7 +4724,10 @@ void MoveDude(spritetype *pSprite)
PLAYER *pPlayer = NULL; PLAYER *pPlayer = NULL;
if (IsPlayerSprite(pSprite)) if (IsPlayerSprite(pSprite))
pPlayer = &gPlayer[pSprite->type-kDudePlayer1]; pPlayer = &gPlayer[pSprite->type-kDudePlayer1];
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax); if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax)) {
consoleSysMsg("pSprite->type >= kDudeBase && pSprite->type < kDudeMax");
return;
}
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase]; DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
int top, bottom; int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom); GetSpriteExtents(pSprite, &top, &bottom);
@ -6141,9 +6151,10 @@ void actProcessSprites(void)
} }
// By NoOne: handle incarnations of custom dude // By NoOne: handle incarnations of custom dude
if (pSprite->type == kDudeModernCustom && pXSprite->txID > 0 && pXSprite->health <= 0 && seqGetStatus(3, nXSprite) < 0) { if (pSprite->type == kDudeModernCustom && pXSprite->txID > 0 && pXSprite->health <= 0 && pXSprite->sysData1 == kGenDudeTransformStatus) {
xvel[pSprite->index] = ClipLow(xvel[pSprite->index] >> 4, 0); yvel[pSprite->index] = ClipLow(yvel[pSprite->index] >> 4, 0);
XSPRITE* pXIncarnation = getNextIncarnation(pXSprite); XSPRITE* pXIncarnation = getNextIncarnation(pXSprite);
if (pXIncarnation != NULL) { if (seqGetStatus(3, nXSprite) < 0 && pXIncarnation != NULL) {
spritetype* pIncarnation = &sprite[pXIncarnation->reference]; spritetype* pIncarnation = &sprite[pXIncarnation->reference];
pXSprite->key = pXSprite->dropMsg = pXSprite->locked = 0; pXSprite->key = pXSprite->dropMsg = pXSprite->locked = 0;
@ -6158,7 +6169,6 @@ void actProcessSprites(void)
// trigger dude death before transform // trigger dude death before transform
trTriggerSprite(nSprite, pXSprite, kCmdOff, pSprite->owner); trTriggerSprite(nSprite, pXSprite, kCmdOff, pSprite->owner);
pSprite->type = pIncarnation->type; pSprite->type = pIncarnation->type;
pSprite->flags = pIncarnation->flags; pSprite->flags = pIncarnation->flags;
pSprite->pal = pIncarnation->pal; pSprite->pal = pIncarnation->pal;
@ -6211,8 +6221,8 @@ void actProcessSprites(void)
break; break;
case kDudeModernCustom: case kDudeModernCustom:
case kDudeModernCustomBurning: case kDudeModernCustomBurning:
seqId = getSeqStartId(pXSprite); seqId = genDudeSeqStartId(pXSprite);
getSpriteMassBySize(pSprite); // create or refresh mass cache genDudePrepare(pSprite, kGenDudePropertyMass);
fallthrough__; // go below fallthrough__; // go below
default: default:
seqSpawn(seqId, 3, nXSprite, -1); seqSpawn(seqId, 3, nXSprite, -1);
@ -7510,7 +7520,7 @@ spritetype* actSpawnCustomDude(spritetype* pSprite, int nDist) {
pXDude->data3 = 0; pXDude->data3 = 0;
// spawn seq // spawn seq
seqSpawn(getSeqStartId(pXDude), 3, pDude->extra, -1); seqSpawn(genDudeSeqStartId(pXDude), 3, pDude->extra, -1);
// inherit movement speed. // inherit movement speed.
pXDude->busyTime = pXSource->busyTime; pXDude->busyTime = pXSource->busyTime;
@ -7550,6 +7560,12 @@ spritetype* actSpawnCustomDude(spritetype* pSprite, int nDist) {
} }
} }
// inherit sprite size (useful for seqs with zero repeats)
if (pSource->flags & kModernTypeFlag2) {
pDude->xrepeat = pSource->xrepeat;
pDude->yrepeat = pSource->yrepeat;
}
aiInitSprite(pDude); aiInitSprite(pDude);
return pDude; return pDude;
} }
@ -7650,7 +7666,7 @@ int getSpriteMassBySize(spritetype* pSprite) {
cached->picnum = pSprite->picnum; cached->seqId = seqId; cached->picnum = pSprite->picnum; cached->seqId = seqId;
cached->clipdist = pSprite->clipdist; cached->clipdist = pSprite->clipdist;
viewSetSystemMessage("MASS: %d", cached->mass); //viewSetSystemMessage("MASS: %d", cached->mass);
return cached->mass; return cached->mass;
} }

View file

@ -110,25 +110,20 @@ void aiPlay3DSound(spritetype *pSprite, int a2, AI_SFX_PRIORITY a3, int a4)
void aiNewState(spritetype *pSprite, XSPRITE *pXSprite, AISTATE *pAIState) void aiNewState(spritetype *pSprite, XSPRITE *pXSprite, AISTATE *pAIState)
{ {
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase]; DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
pXSprite->stateTimer = pAIState->at8; pXSprite->stateTimer = pAIState->stateTicks;
pXSprite->aiState = pAIState; pXSprite->aiState = pAIState;
int seqStartId = pDudeInfo->seqStartID; int seqStartId = pDudeInfo->seqStartID;
if (pAIState->at0 >= 0) { if (pAIState->seqId >= 0) {
// By NoOne: Custom dude uses data2 to keep it's seqStartId seqStartId += pAIState->seqId;
switch (pSprite->type) {
case kDudeModernCustom:
case kDudeModernCustomBurning:
seqStartId = pXSprite->data2;
break;
}
seqStartId += pAIState->at0;
if (gSysRes.Lookup(seqStartId, "SEQ")) if (gSysRes.Lookup(seqStartId, "SEQ"))
seqSpawn(seqStartId, 3, pSprite->extra, pAIState->at4); seqSpawn(seqStartId, 3, pSprite->extra, pAIState->funcId);
} }
if (pAIState->atc) pAIState->atc(pSprite, pXSprite); // entry function if (pAIState->enterFunc)
pAIState->enterFunc(pSprite, pXSprite);
} }
bool dudeIsImmune(spritetype* pSprite, int dmgType) { bool dudeIsImmune(spritetype* pSprite, int dmgType) {
if (dmgType < 0 || dmgType > 6) return true; if (dmgType < 0 || dmgType > 6) return true;
else if (dudeInfo[pSprite->type - kDudeBase].startDamage[dmgType] == 0) return true; else if (dudeInfo[pSprite->type - kDudeBase].startDamage[dmgType] == 0) return true;
@ -417,31 +412,18 @@ void aiActivateDude(spritetype *pSprite, XSPRITE *pXSprite)
pDudeExtraE->at8 = 1; pDudeExtraE->at8 = 1;
pDudeExtraE->at0 = 0; pDudeExtraE->at0 = 0;
if (pXSprite->target == -1) { if (pXSprite->target == -1) {
if (spriteIsUnderwater(pSprite, false)) if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeSearchW);
aiNewState(pSprite, pXSprite, &GDXGenDudeSearchW); else aiGenDudeNewState(pSprite, &genDudeSearchL);
else { } else {
aiNewState(pSprite, pXSprite, &GDXGenDudeSearchL); if (Chance(0x4000)) playGenDudeSound(pSprite, kGenDudeSndTargetSpot);
if (Chance(0x4000)) if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeChaseW);
sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndTargetSpot); else aiGenDudeNewState(pSprite, &genDudeChaseL);
}
}
else {
if (Chance(0x4000))
sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndTargetSpot);
if (spriteIsUnderwater(pSprite, false))
aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW);
else
aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL);
} }
break; break;
} }
case kDudeModernCustomBurning: case kDudeModernCustomBurning:
if (pXSprite->target == -1) if (pXSprite->target == -1) aiGenDudeNewState(pSprite, &genDudeBurnSearch);
aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch); else aiGenDudeNewState(pSprite, &genDudeBurnChase);
else
aiNewState(pSprite, pXSprite, &GDXGenDudeBurnChase);
break; break;
case kDudeCultistTommyProne: { case kDudeCultistTommyProne: {
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1; DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
@ -1026,7 +1008,7 @@ int aiDamageSprite(spritetype *pSprite, XSPRITE *pXSprite, int nSource, DAMAGE_T
break; break;
case kDudeModernCustomBurning: case kDudeModernCustomBurning:
if (Chance(0x2000) && gDudeExtra[pSprite->extra].at0 < (int)gFrameClock) { if (Chance(0x2000) && gDudeExtra[pSprite->extra].at0 < (int)gFrameClock) {
sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndBurning); playGenDudeSound(pSprite, kGenDudeSndBurning);
gDudeExtra[pSprite->extra].at0 = (int)gFrameClock + 360; gDudeExtra[pSprite->extra].at0 = (int)gFrameClock + 360;
} }
if (pXSprite->burnTime == 0) pXSprite->burnTime = 2400; if (pXSprite->burnTime == 0) pXSprite->burnTime = 2400;
@ -1034,17 +1016,18 @@ int aiDamageSprite(spritetype *pSprite, XSPRITE *pXSprite, int nSource, DAMAGE_T
pSprite->type = kDudeModernCustom; pSprite->type = kDudeModernCustom;
pXSprite->burnTime = 0; pXSprite->burnTime = 0;
pXSprite->health = 1; // so it can be killed with flame weapons while underwater and if already was burning dude before. pXSprite->health = 1; // so it can be killed with flame weapons while underwater and if already was burning dude before.
aiNewState(pSprite, pXSprite, &GDXGenDudeGotoW); aiGenDudeNewState(pSprite, &genDudeGotoW);
} }
break; break;
case kDudeModernCustom: case kDudeModernCustom: {
{ GENDUDEEXTRA* pExtra = genDudeExtra(pSprite);
if (nDmgType == DAMAGE_TYPE_1) { if (nDmgType == DAMAGE_TYPE_1) {
if (pXSprite->health <= pDudeInfo->fleeHealth) { if (pXSprite->health > pDudeInfo->fleeHealth) break;
if (pXSprite->txID <= 0 || getNextIncarnation(pXSprite) == NULL) { else if (pXSprite->txID <= 0 || getNextIncarnation(pXSprite) == NULL) {
removeDudeStuff(pSprite); removeDudeStuff(pSprite);
if (pXSprite->data1 >= kTrapExploder && pXSprite->data1 < (kTrapExploder + kExplodeMax) - 1) if (pExtra->curWeapon >= kTrapExploder && pExtra->curWeapon < (kTrapExploder + kExplodeMax) - 1)
doExplosion(pSprite, pXSprite->data1 - kTrapExploder); doExplosion(pSprite, pXSprite->data1 - kTrapExploder);
if (spriteIsUnderwater(pSprite, false)) { if (spriteIsUnderwater(pSprite, false)) {
@ -1055,17 +1038,16 @@ int aiDamageSprite(spritetype *pSprite, XSPRITE *pXSprite, int nSource, DAMAGE_T
if (pXSprite->burnTime <= 0) if (pXSprite->burnTime <= 0)
pXSprite->burnTime = 1200; pXSprite->burnTime = 1200;
if ((gSysRes.Lookup(pXSprite->data2 + 15, "SEQ") || gSysRes.Lookup(pXSprite->data2 + 16, "SEQ")) if (pExtra->canBurn && pExtra->availDeaths[DAMAGE_TYPE_1] > 0) {
&& gSysRes.Lookup(pXSprite->data2 + 3, "SEQ")) {
aiPlay3DSound(pSprite, 361, AI_SFX_PRIORITY_0, -1); aiPlay3DSound(pSprite, 361, AI_SFX_PRIORITY_0, -1);
sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndBurning); playGenDudeSound(pSprite, kGenDudeSndBurning);
pSprite->type = kDudeModernCustomBurning; pSprite->type = kDudeModernCustomBurning;
if (pXSprite->data2 == kDefaultAnimationBase) // don't inherit palette for burning if using default animation if (pXSprite->data2 == kGenDudeDefaultSeq) // don't inherit palette for burning if using default animation
pSprite->pal = 0; pSprite->pal = 0;
aiNewState(pSprite, pXSprite, &GDXGenDudeBurnGoto); aiGenDudeNewState(pSprite, &genDudeBurnGoto);
actHealDude(pXSprite, dudeInfo[55].startHealth, dudeInfo[55].startHealth); actHealDude(pXSprite, dudeInfo[55].startHealth, dudeInfo[55].startHealth);
gDudeExtra[pSprite->extra].at0 = (int)gFrameClock + 360; gDudeExtra[pSprite->extra].at0 = (int)gFrameClock + 360;
evKill(nSprite, 3, kCallbackFXFlameLick); evKill(nSprite, 3, kCallbackFXFlameLick);
@ -1075,22 +1057,20 @@ int aiDamageSprite(spritetype *pSprite, XSPRITE *pXSprite, int nSource, DAMAGE_T
} else { } else {
actKillDude(nSource, pSprite, DAMAGE_TYPE_0, 65535); actKillDude(nSource, pSprite, DAMAGE_TYPE_0, 65535);
} }
} } else if (canWalk(pSprite) && !inDodge(pXSprite->aiState) && !inRecoil(pXSprite->aiState)) {
} else if (!inDodge(pXSprite->aiState)) { if (inIdle(pXSprite->aiState) || inSearch(pXSprite->aiState) || Chance(getDodgeChance(pSprite))) {
if (Chance(getDodgeChance(pSprite)) || inIdle(pXSprite->aiState)) {
if (!spriteIsUnderwater(pSprite, false)) { if (!spriteIsUnderwater(pSprite, false)) {
if (!canDuck(pSprite) || !sub_5BDA8(pSprite, 14)) aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeDmgL); if (!canDuck(pSprite) || !sub_5BDA8(pSprite, 14)) aiGenDudeNewState(pSprite, &genDudeDodgeShortL);
else aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeDmgD); else aiGenDudeNewState(pSprite, &genDudeDodgeShortD);
if (Chance(0x0200)) if (Chance(0x0200))
sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndGotHit); playGenDudeSound(pSprite, kGenDudeSndGotHit);
}
else if (sub_5BDA8(pSprite, 13))
aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeDmgW);
}
}
} else if (sub_5BDA8(pSprite, 13)) {
aiGenDudeNewState(pSprite, &genDudeDodgeShortW);
}
}
}
break; break;
} }
case kDudeCultistBeast: case kDudeCultistBeast:
@ -1123,43 +1103,53 @@ void RecoilDude(spritetype *pSprite, XSPRITE *pXSprite)
{ {
char v4 = Chance(0x8000); char v4 = Chance(0x8000);
DUDEEXTRA *pDudeExtra = &gDudeExtra[pSprite->extra]; DUDEEXTRA *pDudeExtra = &gDudeExtra[pSprite->extra];
if (pSprite->statnum == kStatDude && (pSprite->type >= kDudeBase && pSprite->type < kDudeMax)) if (pSprite->statnum == kStatDude && (pSprite->type >= kDudeBase && pSprite->type < kDudeMax)) {
{
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase]; DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
switch (pSprite->type) switch (pSprite->type) {
{ case kDudeModernCustom: {
case kDudeModernCustom: GENDUDEEXTRA* pExtra = genDudeExtra(pSprite); int rChance = getRecoilChance(pSprite);
{ if (pExtra->canElectrocute && pDudeExtra->at4 && !spriteIsUnderwater(pSprite, false)) {
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, kGenDudeSndGotHit);
if (gSysRes.Lookup(pXSprite->data2 + 4, "SEQ")) { if (Chance(rChance << 3) || (dudeIsMelee(pXSprite) && Chance(rChance << 4))) aiGenDudeNewState(pSprite, &genDudeRecoilTesla);
GDXGenDudeRTesla.at18 = (Chance(chance4 * 2) ? &GDXGenDudeDodgeL : &GDXGenDudeDodgeDmgL); else if (pExtra->canRecoil && Chance(rChance)) aiGenDudeNewState(pSprite, &genDudeRecoilL);
aiNewState(pSprite, pXSprite, &GDXGenDudeRTesla); else if (canWalk(pSprite)) {
}
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);
break;
}
if (inDodge(pXSprite->aiState)) { if (Chance(rChance >> 2)) aiGenDudeNewState(pSprite, &genDudeDodgeL);
sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndGotHit); else if (Chance(rChance >> 1)) aiGenDudeNewState(pSprite, &genDudeDodgeShortL);
break;
}
if (inIdle(pXSprite->aiState) || chance3 || Chance(getRecoilChance(pSprite)) || (!dudeIsMelee(pXSprite) && mass < 155)) {
sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndGotHit);
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);
} }
} else if (pExtra->canRecoil && Chance(rChance)) {
if (inDuck(pXSprite->aiState) && Chance(rChance >> 2)) aiGenDudeNewState(pSprite, &genDudeRecoilD);
else if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeRecoilW);
else aiGenDudeNewState(pSprite, &genDudeRecoilL);
}
short rState = inRecoil(pXSprite->aiState);
if (rState > 0) {
if (!canWalk(pSprite)) {
if (rState == 1) pXSprite->aiState->nextState = &genDudeChaseNoWalkL;
else if (rState == 2) pXSprite->aiState->nextState = &genDudeChaseNoWalkD;
else pXSprite->aiState->nextState = &genDudeChaseNoWalkW;
} else if (!dudeIsMelee(pXSprite) || Chance(rChance >> 2)) {
if (rState == 1) pXSprite->aiState->nextState = (Chance(rChance) ? &genDudeDodgeL : &genDudeDodgeShortL);
else if (rState == 2) pXSprite->aiState->nextState = (Chance(rChance) ? &genDudeDodgeD : &genDudeDodgeShortD);
else if (rState == 1) pXSprite->aiState->nextState = (Chance(rChance) ? &genDudeDodgeW : &genDudeDodgeShortW);
}
else if (rState == 1) pXSprite->aiState->nextState = &genDudeChaseL;
else if (rState == 2) pXSprite->aiState->nextState = &genDudeChaseD;
else pXSprite->aiState->nextState = &genDudeChaseW;
playGenDudeSound(pSprite, kGenDudeSndGotHit);
}
pDudeExtra->at4 = 0;
break; break;
} }
case kDudeCultistTommy: case kDudeCultistTommy:
@ -1193,7 +1183,7 @@ void RecoilDude(spritetype *pSprite, XSPRITE *pXSprite)
aiNewState(pSprite, pXSprite, &cultistBurnGoto); aiNewState(pSprite, pXSprite, &cultistBurnGoto);
break; break;
case kDudeModernCustomBurning: case kDudeModernCustomBurning:
aiNewState(pSprite, pXSprite, &GDXGenDudeBurnGoto); aiGenDudeNewState(pSprite, &genDudeBurnGoto);
break; break;
case kDudeZombieButcher: case kDudeZombieButcher:
aiPlay3DSound(pSprite, 1202, AI_SFX_PRIORITY_2, -1); aiPlay3DSound(pSprite, 1202, AI_SFX_PRIORITY_2, -1);
@ -1453,26 +1443,31 @@ void sub_5F15C(spritetype *pSprite, XSPRITE *pXSprite)
} }
} }
void aiProcessDudes(void) void aiProcessDudes(void) {
{
for (int nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite]) { for (int nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
spritetype *pSprite = &sprite[nSprite]; spritetype *pSprite = &sprite[nSprite];
if (pSprite->flags & 32) continue; if (pSprite->flags & 32) continue;
int nXSprite = pSprite->extra; int nXSprite = pSprite->extra;
XSPRITE *pXSprite = &xsprite[nXSprite]; XSPRITE *pXSprite = &xsprite[nXSprite]; DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
if (IsPlayerSprite(pSprite) || pXSprite->health == 0) continue; if (IsPlayerSprite(pSprite) || pXSprite->health == 0) continue;
pXSprite->stateTimer = ClipLow(pXSprite->stateTimer-4, 0); pXSprite->stateTimer = ClipLow(pXSprite->stateTimer-4, 0);
if (pXSprite->aiState->at10) if (pSprite->type >= kDudeVanillaMax && pSprite->type < kDudeMax)
pXSprite->aiState->at10(pSprite, pXSprite); genDudeProcess(pSprite, pXSprite);
if (pXSprite->aiState->at14 && (gFrame&3) == (nSprite&3))
pXSprite->aiState->at14(pSprite, pXSprite); else {
if (pXSprite->stateTimer == 0 && pXSprite->aiState->at18) {
if (pXSprite->aiState->at8 > 0) if (pXSprite->aiState->moveFunc)
aiNewState(pSprite, pXSprite, pXSprite->aiState->at18); pXSprite->aiState->moveFunc(pSprite, pXSprite);
if (pXSprite->aiState->thinkFunc && (gFrame & 3) == (nSprite & 3))
pXSprite->aiState->thinkFunc(pSprite, pXSprite);
if (pXSprite->stateTimer == 0 && pXSprite->aiState->nextState) {
if (pXSprite->aiState->stateTicks > 0)
aiNewState(pSprite, pXSprite, pXSprite->aiState->nextState);
else if (seqGetStatus(3, nXSprite) < 0) else if (seqGetStatus(3, nXSprite) < 0)
aiNewState(pSprite, pXSprite, pXSprite->aiState->at18); aiNewState(pSprite, pXSprite, pXSprite->aiState->nextState);
} }
if (pXSprite->health > 0 && ((pDudeInfo->hinderDamage << 4) <= cumulDamage[nXSprite])) { if (pXSprite->health > 0 && ((pDudeInfo->hinderDamage << 4) <= cumulDamage[nXSprite])) {
@ -1480,19 +1475,8 @@ void aiProcessDudes(void)
RecoilDude(pSprite, pXSprite); RecoilDude(pSprite, pXSprite);
} }
if (pSprite->type >= kDudeVanillaMax) {
switch (pSprite->type) {
case kDudeModernCustom:
case kDudeModernCustomBurning:
GENDUDEEXTRA* pExtra = &gGenDudeExtra[pSprite->index];
if (pExtra->slaveCount > 0) updateTargetOfSlaves(pSprite);
if (pExtra->nLifeLeech >= 0) updateTargetOfLeech(pSprite);
break;
} }
} }
}
memset(cumulDamage, 0, sizeof(cumulDamage)); memset(cumulDamage, 0, sizeof(cumulDamage));
} }
@ -1520,12 +1504,12 @@ void aiInitSprite(spritetype *pSprite)
case kDudeModernCustom: { case kDudeModernCustom: {
DUDEEXTRA_at6_u1* pDudeExtraE = &gDudeExtra[nXSprite].at6.u1; DUDEEXTRA_at6_u1* pDudeExtraE = &gDudeExtra[nXSprite].at6.u1;
pDudeExtraE->at8 = pDudeExtraE->at0 = 0; pDudeExtraE->at8 = pDudeExtraE->at0 = 0;
aiNewState(pSprite, pXSprite, &GDXGenDudeIdleL); aiGenDudeNewState(pSprite, &genDudeIdleL);
genDudePrepare(pSprite); genDudePrepare(pSprite);
break; break;
} }
case kDudeModernCustomBurning: case kDudeModernCustomBurning:
aiNewState(pSprite, pXSprite, &GDXGenDudeBurnGoto); aiGenDudeNewState(pSprite, &genDudeBurnGoto);
pXSprite->burnTime = 1200; pXSprite->burnTime = 1200;
break; break;
case kDudeCultistTommy: case kDudeCultistTommy:

View file

@ -32,13 +32,13 @@ BEGIN_BLD_NS
struct AISTATE { struct AISTATE {
int stateType; // By NoOne: current type of state. Basically required for kModernDudeTargetChanger, but can be used for something else. int stateType; // By NoOne: current type of state. Basically required for kModernDudeTargetChanger, but can be used for something else.
int at0; // seq int seqId;
int at4; // seq callback int funcId; // seq callback
int at8; int stateTicks;
void(*atc)(spritetype *, XSPRITE *); void(*enterFunc)(spritetype *, XSPRITE *);
void(*at10)(spritetype *, XSPRITE *); void(*moveFunc)(spritetype *, XSPRITE *);
void(*at14)(spritetype *, XSPRITE *); void(*thinkFunc)(spritetype *, XSPRITE *);
AISTATE *at18; // next state ? AISTATE *nextState;
}; };
extern AISTATE aiState[]; extern AISTATE aiState[];
@ -86,6 +86,7 @@ struct TARGETTRACK {
extern int dword_138BB0[5]; extern int dword_138BB0[5];
extern DUDEEXTRA gDudeExtra[]; extern DUDEEXTRA gDudeExtra[];
extern int gDudeSlope[]; extern int gDudeSlope[];
extern int cumulDamage[];
bool sub_5BDA8(spritetype *pSprite, int nSeq); bool sub_5BDA8(spritetype *pSprite, int nSeq);
void aiPlay3DSound(spritetype *pSprite, int a2, AI_SFX_PRIORITY a3, int a4); void aiPlay3DSound(spritetype *pSprite, int a2, AI_SFX_PRIORITY a3, int a4);
@ -104,6 +105,7 @@ void aiProcessDudes(void);
void aiInit(void); void aiInit(void);
void aiInitSprite(spritetype *pSprite); void aiInitSprite(spritetype *pSprite);
bool CanMove(spritetype* pSprite, int a2, int nAngle, int nRange); bool CanMove(spritetype* pSprite, int a2, int nAngle, int nRange);
void RecoilDude(spritetype* pSprite, XSPRITE* pXSprite);
// By NoOne: this function required for kModernDudeTargetChanger // By NoOne: this function required for kModernDudeTargetChanger
void aiSetGenIdleState(spritetype* pSprite, XSPRITE* pXSprite); void aiSetGenIdleState(spritetype* pSprite, XSPRITE* pXSprite);

View file

@ -81,11 +81,11 @@ AISTATE tinycalebBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, th
AISTATE tinycalebBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, &tinycalebBurnSearch }; AISTATE tinycalebBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, &tinycalebBurnSearch };
AISTATE tinycalebBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &tinycalebBurnChase }; AISTATE tinycalebBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &tinycalebBurnChase };
AISTATE GDXGenDudeBurnIdle = { kAiStateIdle, 3, -1, 0, NULL, NULL, aiThinkTarget, NULL }; AISTATE genDudeBurnIdle = { kAiStateIdle, 3, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE GDXGenDudeBurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL }; AISTATE genDudeBurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE GDXGenDudeBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &GDXGenDudeBurnSearch }; AISTATE genDudeBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &genDudeBurnSearch };
AISTATE GDXGenDudeBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, &GDXGenDudeBurnSearch }; AISTATE genDudeBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, &genDudeBurnSearch };
AISTATE GDXGenDudeBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &GDXGenDudeBurnChase }; AISTATE genDudeBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &genDudeBurnChase };
static void BurnSeqCallback(int, int) static void BurnSeqCallback(int, int)
{ {
@ -129,7 +129,7 @@ static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
aiNewState(pSprite, pXSprite, &tinycalebBurnSearch); aiNewState(pSprite, pXSprite, &tinycalebBurnSearch);
break; break;
case kDudeModernCustomBurning: case kDudeModernCustomBurning:
aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch); aiNewState(pSprite, pXSprite, &genDudeBurnSearch);
break; break;
} }
} }
@ -161,7 +161,7 @@ static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
aiNewState(pSprite, pXSprite, &tinycalebBurnGoto); aiNewState(pSprite, pXSprite, &tinycalebBurnGoto);
break; break;
case kDudeModernCustomBurning: case kDudeModernCustomBurning:
aiNewState(pSprite, pXSprite, &GDXGenDudeBurnGoto); aiNewState(pSprite, pXSprite, &genDudeBurnGoto);
break; break;
} }
return; return;
@ -197,7 +197,7 @@ static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
aiNewState(pSprite, pXSprite, &tinycalebBurnSearch); aiNewState(pSprite, pXSprite, &tinycalebBurnSearch);
break; break;
case kDudeModernCustomBurning: case kDudeModernCustomBurning:
aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch); aiNewState(pSprite, pXSprite, &genDudeBurnSearch);
break; break;
} }
return; return;
@ -235,7 +235,7 @@ static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
aiNewState(pSprite, pXSprite, &tinycalebBurnAttack); aiNewState(pSprite, pXSprite, &tinycalebBurnAttack);
break; break;
case kDudeModernCustomBurning: case kDudeModernCustomBurning:
aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch); aiNewState(pSprite, pXSprite, &genDudeBurnSearch);
break; break;
} }
} }
@ -265,7 +265,7 @@ static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
aiNewState(pSprite, pXSprite, &tinycalebBurnGoto); aiNewState(pSprite, pXSprite, &tinycalebBurnGoto);
break; break;
case kDudeModernCustomBurning: case kDudeModernCustomBurning:
aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch); aiNewState(pSprite, pXSprite, &genDudeBurnSearch);
break; break;
} }
pXSprite->target = -1; pXSprite->target = -1;

View file

@ -50,10 +50,10 @@ extern AISTATE tinycalebBurnChase;
extern AISTATE tinycalebBurnGoto; extern AISTATE tinycalebBurnGoto;
extern AISTATE tinycalebBurnSearch; extern AISTATE tinycalebBurnSearch;
extern AISTATE tinycalebBurnAttack; extern AISTATE tinycalebBurnAttack;
extern AISTATE GDXGenDudeBurnIdle; extern AISTATE genDudeBurnIdle;
extern AISTATE GDXGenDudeBurnChase; extern AISTATE genDudeBurnChase;
extern AISTATE GDXGenDudeBurnGoto; extern AISTATE genDudeBurnGoto;
extern AISTATE GDXGenDudeBurnSearch; extern AISTATE genDudeBurnSearch;
extern AISTATE GDXGenDudeBurnAttack; extern AISTATE genDudeBurnAttack;
END_BLD_NS END_BLD_NS

File diff suppressed because it is too large Load diff

View file

@ -26,9 +26,40 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "eventq.h" #include "eventq.h"
BEGIN_BLD_NS BEGIN_BLD_NS
#define kGenDudeDefaultSeq 11520
#define kDefaultAnimationBase 11520
#define kGenDudeMaxSlaves 7 #define kGenDudeMaxSlaves 7
#define kGenDudeTransformStatus -222
#define kGenDudeUpdTimeRate 10
#define kGenDudeMaxMeleeDist 2048
enum {
kGenDudeSeqIdleL = 0,
kGenDudeSeqDeathDefault = 1,
kGenDudeSeqDeathExplode = 2,
kGenDudeSeqBurning = 3,
kGenDudeSeqElectocuted = 4,
kGenDudeSeqRecoil = 5,
kGenDudeSeqAttackNormalL = 6,
kGenDudeSeqAttackThrow = 7,
kGenDudeSeqAttackNormalDW = 8,
kGenDudeSeqMoveL = 9,
kGenDudeSeqAttackPunch = 10,
kGenDudeSeqReserved1 = 11,
kGenDudeSeqReserved2 = 12,
kGenDudeSeqMoveW = 13,
kGenDudeSeqMoveD = 14,
kGenDudeSeqDeathBurn1 = 15,
kGenDudeSeqDeathBurn2 = 16,
kGenDudeSeqIdleW = 17,
kGenDudeSeqTransform = 18,
kGenDudeSeqReserved3 = 19,
kGenDudeSeqReserved4 = 20,
kGenDudeSeqReserved5 = 21,
kGenDudeSeqReserved6 = 22,
kGenDudeSeqReserved7 = 23,
kGenDudeSeqReserved8 = 24,
kGenDudeSeqMax ,
};
enum { enum {
kGenDudeSndTargetSpot = 0, kGenDudeSndTargetSpot = 0,
@ -48,44 +79,47 @@ kGenDudeSndMax ,
enum { enum {
kGenDudePropertyAll = 0, kGenDudePropertyAll = 0,
kGenDudePropertyWeapon = 1, kGenDudePropertyWeapon = 1,
kGenDudePropertyDamage = 2, kGenDudePropertyDmgScale = 2,
kGenDudePropertyMass = 3, kGenDudePropertyMass = 3,
kGenDudePropertyAttack = 4, kGenDudePropertyAttack = 4,
kGenDudePropertyStates = 5, kGenDudePropertyStates = 5,
kGenDudePropertyLeech = 6, kGenDudePropertyLeech = 6,
kGenDudePropertySlaves = 7, kGenDudePropertySlaves = 7,
kGenDudePropertyMelee = 8, kGenDudePropertySpriteSize = 8,
kGenDudePropertyClipdist = 9, kGenDudePropertyInitVals = 9,
kGenDudePropertyMax , kGenDudePropertyMax ,
}; };
extern AISTATE genDudeIdleL;
extern AISTATE GDXGenDudeIdleL; extern AISTATE genDudeIdleW;
extern AISTATE GDXGenDudeIdleW; extern AISTATE genDudeSearchL;
extern AISTATE GDXGenDudeSearchL; extern AISTATE genDudeSearchW;
extern AISTATE GDXGenDudeSearchW; extern AISTATE genDudeGotoL;
extern AISTATE GDXGenDudeGotoL; extern AISTATE genDudeGotoW;
extern AISTATE GDXGenDudeGotoW; extern AISTATE genDudeDodgeL;
extern AISTATE GDXGenDudeDodgeL; extern AISTATE genDudeDodgeD;
extern AISTATE GDXGenDudeDodgeD; extern AISTATE genDudeDodgeW;
extern AISTATE GDXGenDudeDodgeW; extern AISTATE genDudeDodgeShortL;
extern AISTATE GDXGenDudeDodgeDmgL; extern AISTATE genDudeDodgeShortD;
extern AISTATE GDXGenDudeDodgeDmgD; extern AISTATE genDudeDodgeShortW;
extern AISTATE GDXGenDudeDodgeDmgW; extern AISTATE genDudeChaseL;
extern AISTATE GDXGenDudeChaseL; extern AISTATE genDudeChaseD;
extern AISTATE GDXGenDudeChaseD; extern AISTATE genDudeChaseW;
extern AISTATE GDXGenDudeChaseW; extern AISTATE genDudeFireL;
extern AISTATE GDXGenDudeFireL; extern AISTATE genDudeFireD;
extern AISTATE GDXGenDudeFireD; extern AISTATE genDudeFireW;
extern AISTATE GDXGenDudeFireW; extern AISTATE genDudeRecoilL;
extern AISTATE GDXGenDudeRecoilL; extern AISTATE genDudeRecoilD;
extern AISTATE GDXGenDudeRecoilD; extern AISTATE genDudeRecoilW;
extern AISTATE GDXGenDudeRecoilW; extern AISTATE genDudeThrow;
extern AISTATE GDXGenDudeThrow; extern AISTATE genDudeThrow2;
extern AISTATE GDXGenDudeThrow2; extern AISTATE genDudePunch;
extern AISTATE GDXGenDudePunch; extern AISTATE genDudeRecoilTesla;
extern AISTATE GDXGenDudeRTesla; extern AISTATE genDudeSearchNoWalkL;
extern AISTATE GDXGenDudeTransform; extern AISTATE genDudeSearchNoWalkW;
extern AISTATE genDudeChaseNoWalkL;
extern AISTATE genDudeChaseNoWalkD;
extern AISTATE genDudeChaseNoWalkW;
struct GENDUDESND struct GENDUDESND
{ {
@ -93,6 +127,7 @@ struct GENDUDESND
int randomRange; int randomRange;
int sndIdOffset; // relative to data3 int sndIdOffset; // relative to data3
bool aiPlaySound; // false = sfxStart3DSound(); bool aiPlaySound; // false = sfxStart3DSound();
bool interruptable;
}; };
extern GENDUDESND gCustomDudeSnd[]; extern GENDUDESND gCustomDudeSnd[];
@ -105,29 +140,41 @@ struct GENDUDEEXTRA {
unsigned short curWeapon; // data1 duplicate to avoid potential problems when changing data dynamically unsigned short curWeapon; // data1 duplicate to avoid potential problems when changing data dynamically
unsigned short baseDispersion; unsigned short baseDispersion;
signed short nLifeLeech; // spritenum of dropped dude's leech signed short nLifeLeech; // spritenum of dropped dude's leech
short dmgControl[kDamageMax]; // depends of current weapon, drop armor item and sprite yrepeat
short slave[kGenDudeMaxSlaves]; // index of the ones dude is summon
short slaveCount; short slaveCount;
short slave[kGenDudeMaxSlaves]; // index of the ones dude is summon
short dmgControl[kDamageMax]; // depends of current weapon, drop armor item, sprite yrepeat and surface type
short availDeaths[kDamageMax]; // list of seqs with deaths for each damage type
short initVals[3]; // xrepeat, yrepeat, clipdist
bool forcePunch; // indicate if there is no fire trigger in punch state seq
bool updReq[kGenDudePropertyMax]; // update requests bool updReq[kGenDudePropertyMax]; // update requests
bool sndPlaying; // indicate if sound of AISTATE currently playing
bool isMelee; bool isMelee;
bool canBurn; // can turn in Burning dude or not
bool canElectrocute;
bool canAttack;
bool canRecoil;
bool canWalk; bool canWalk;
bool canDuck; bool canDuck;
bool canSwim; bool canSwim;
bool canFly; bool canFly;
}; };
extern GENDUDEEXTRA gGenDudeExtra[]; extern GENDUDEEXTRA gGenDudeExtra[];
inline GENDUDEEXTRA* genDudeExtra(spritetype* pSprite) {
return &gGenDudeExtra[pSprite->index];
}
XSPRITE* getNextIncarnation(XSPRITE* pXSprite); XSPRITE* getNextIncarnation(XSPRITE* pXSprite);
void killDudeLeech(spritetype* pLeech); void killDudeLeech(spritetype* pLeech);
void removeLeech(spritetype* pLeech, bool delSprite = true); void removeLeech(spritetype* pLeech, bool delSprite = true);
void removeDudeStuff(spritetype* pSprite); void removeDudeStuff(spritetype* pSprite);
spritetype* leechIsDropped(spritetype* pSprite); spritetype* leechIsDropped(spritetype* pSprite);
bool spriteIsUnderwater(spritetype* pSprite, bool oldWay); bool spriteIsUnderwater(spritetype* pSprite, bool oldWay = false);
bool sfxPlayGDXGenDudeSound(spritetype* pSprite, int mode); bool playGenDudeSound(spritetype* pSprite, int mode, bool forceInterrupt = false);
void aiGenDudeMoveForward(spritetype* pSprite, XSPRITE* pXSprite); void aiGenDudeMoveForward(spritetype* pSprite, XSPRITE* pXSprite);
void aiGenDudeChooseDirection(spritetype* pSprite, XSPRITE* pXSprite, int a3, int aXvel = -1, int aYvel = -1); void aiGenDudeChooseDirection(spritetype* pSprite, XSPRITE* pXSprite, int a3, int aXvel = -1, int aYvel = -1);
void aiGenDudeNewState(spritetype* pSprite, AISTATE* pAIState);
int getGenDudeMoveSpeed(spritetype* pSprite, int which, bool mul, bool shift); int getGenDudeMoveSpeed(spritetype* pSprite, int which, bool mul, bool shift);
bool TargetNearThing(spritetype* pSprite, int thingType); bool TargetNearThing(spritetype* pSprite, int thingType);
int checkAttackState(spritetype* pSprite, XSPRITE* pXSprite); int checkAttackState(spritetype* pSprite, XSPRITE* pXSprite);
@ -143,12 +190,16 @@ bool canDuck(spritetype* pSprite);
bool canWalk(spritetype* pSprite); bool canWalk(spritetype* pSprite);
bool inDodge(AISTATE* aiState); bool inDodge(AISTATE* aiState);
bool inIdle(AISTATE* aiState); bool inIdle(AISTATE* aiState);
int getSeqStartId(XSPRITE* pXSprite); bool inAttack(AISTATE* aiState);
int getSeeDist(spritetype* pSprite, int startDist, int minDist, int maxDist); short inRecoil(AISTATE* aiState);
short inSearch(AISTATE* aiState);
short inDuck(AISTATE* aiState);
int genDudeSeqStartId(XSPRITE* pXSprite);
int getRangeAttackDist(spritetype* pSprite, int minDist = 1200, int maxDist = 80000); int getRangeAttackDist(spritetype* pSprite, int minDist = 1200, int maxDist = 80000);
int getDispersionModifier(spritetype* pSprite, int minDisp, int maxDisp); int getDispersionModifier(spritetype* pSprite, int minDisp, int maxDisp);
void scaleDamage(XSPRITE* pXSprite); void scaleDamage(XSPRITE* pXSprite);
void genDudePrepare(spritetype* pSprite, int propId = kGenDudePropertyAll); bool genDudePrepare(spritetype* pSprite, int propId = kGenDudePropertyAll);
void genDudeUpdate(spritetype* pSprite); void genDudeUpdate(spritetype* pSprite);
void genDudeProcess(spritetype* pSprite, XSPRITE* pXSprite);
END_BLD_NS END_BLD_NS

View file

@ -608,6 +608,7 @@ void StartLevel(GAMEOPTIONS *gameOptions)
case kModernObjDataAccumulator: case kModernObjDataAccumulator:
case kModernEffectSpawner: case kModernEffectSpawner:
case kModernWindGenerator: case kModernWindGenerator:
case kModernPlayerControl:
pSprite->type = kSpriteDecoration; pSprite->type = kSpriteDecoration;
break; break;
case kItemModernMapLevel: case kItemModernMapLevel:

View file

@ -45,6 +45,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "trig.h" #include "trig.h"
#include "triggers.h" #include "triggers.h"
#include "view.h" #include "view.h"
#include "aiunicult.h"
BEGIN_BLD_NS BEGIN_BLD_NS
@ -763,6 +764,12 @@ void makeMissileBlocking(int nSprite) // 23
sprite[nSprite].cstat |= CSTAT_SPRITE_BLOCK; sprite[nSprite].cstat |= CSTAT_SPRITE_BLOCK;
} }
void genDudeUpdateCallback(int nSprite) // 24
{
if (spriRangeIsFine(nSprite))
genDudeUpdate(&sprite[nSprite]);
}
void(*gCallback[kCallbackMax])(int) = void(*gCallback[kCallbackMax])(int) =
{ {
fxFlameLick, fxFlameLick,
@ -789,6 +796,7 @@ void(*gCallback[kCallbackMax])(int) =
DropVoodoo, // unused DropVoodoo, // unused
UniMissileBurst, UniMissileBurst,
makeMissileBlocking, makeMissileBlocking,
genDudeUpdateCallback,
}; };
END_BLD_NS END_BLD_NS

View file

@ -51,6 +51,7 @@ enum CALLBACK_ID {
kCallbackDropVoodoo = 21, // unused kCallbackDropVoodoo = 21, // unused
kCallbackMissileBurst = 22, // by NoOne kCallbackMissileBurst = 22, // by NoOne
kCallbackMissileSpriteBlock = 23, // by NoOne kCallbackMissileSpriteBlock = 23, // by NoOne
kCallbackGenDudeUpdate = 24, // by NoOne
kCallbackMax, kCallbackMax,
}; };

View file

@ -436,6 +436,17 @@ enum {
kSectorMax = 620, kSectorMax = 620,
}; };
// ai state types
enum {
kAiStateOther = -1,
kAiStateIdle = 0,
kAiStateGenIdle = 1,
kAiStateMove = 2,
kAiStateSearch = 3,
kAiStateChase = 4,
kAiStateRecoil = 5,
kAiStateAttack = 6,
};
// sprite attributes // sprite attributes
#define kHitagAutoAim 0x0008 #define kHitagAutoAim 0x0008
@ -472,16 +483,6 @@ enum {
#define kSecCFloorShade 0x8000 #define kSecCFloorShade 0x8000
// ai state types
#define kAiStateOther -1
#define kAiStateIdle 0
#define kAiStateGenIdle 1
#define kAiStateMove 2
#define kAiStateSearch 3
#define kAiStateChase 4
#define kAiStateRecoil 5
#define kAng5 28 #define kAng5 28
#define kAng15 85 #define kAng15 85
#define kAng30 170 #define kAng30 170

View file

@ -32,7 +32,7 @@ BEGIN_BLD_NS
#define kMaxSuperXSprites 128 #define kMaxSuperXSprites 128
// by NoOne: functions to quckly check range of specifical arrays // by NoOne: functions to quckly check range of specifical arrays
inline bool xsprRangeIsFine(int nXindex) { inline bool xspriRangeIsFine(int nXindex) {
return (nXindex >= 0 && nXindex < kMaxXSprites); return (nXindex >= 0 && nXindex < kMaxXSprites);
} }
@ -44,6 +44,10 @@ inline bool xwallRangeIsFine(int nXindex) {
return (nXindex >= 0 && nXindex < kMaxXWalls); return (nXindex >= 0 && nXindex < kMaxXWalls);
} }
inline bool xspriIsFine(int nIndex) {
return (nIndex >= 0 && nIndex < kMaxSprites && !(sprite[nIndex].flags & 32) && sprite[nIndex].statnum != kStatFree);
}
extern bool gModernMap; extern bool gModernMap;
#pragma pack(push, 1) #pragma pack(push, 1)

View file

@ -1544,7 +1544,7 @@ DUDEINFO dudeInfo[kDudeMax-kDudeBase] =
0, 0,
0 0
}, },
//254 - kGDXUniversalCultist //254 - kDudeModernCustom
{ {
11520, // start sequence ID 11520, // start sequence ID
85, // start health 85, // start health
@ -1570,12 +1570,12 @@ DUDEINFO dudeInfo[kDudeMax-kDudeBase] =
256, // angSpeed 256, // angSpeed
// 0, // 0,
7, -1, 18, // nGibType 7, -1, 18, // nGibType
128, 128, 128, 128, 128, 128, 128, 128, 150, 128, 256, 128, 128, 128,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
0 0
}, },
//255 - kGDXGenDudeBurning //255 - kDudeModernCustomBurning
{ {
4096, // start sequence ID 4096, // start sequence ID
25, // start health 25, // start health

View file

@ -158,45 +158,6 @@ void CKillMgr::sub_2641C(void)
} }
} }
/*
void CKillMgr::AddKill(spritetype *pSprite) {
if (pSprite->statnum == kStatDude) {
switch (pSprite->type) {
case kDudeBat:
case kDudeRat:
case kDudeBurningInnocent:
case kDudeInnocent:
return;
}
at4++;
}
}
void CKillMgr::sub_2641C(void)
{
at0 = 0;
for (int nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
spritetype *pSprite = &sprite[nSprite];
if (IsDudeSprite(pSprite)) {
if (pSprite->statnum == kStatDude) {
switch (pSprite->type) {
case kDudeBat:
case kDudeRat:
case kDudeBurningInnocent:
case kDudeInnocent:
return;
}
at0++;
}
}
}
}
*/
void CKillMgr::Draw(void) void CKillMgr::Draw(void)
{ {
char pBuffer[40]; char pBuffer[40];

View file

@ -427,11 +427,12 @@ void evSend(int nIndex, int nType, int rxId, COMMAND_ID command, short causedBy)
break; break;
} }
//by NoOne: allow to send commands on player sprites
if (gModernMap) { if (gModernMap) {
// allow to send commands on player sprites
PLAYER* pPlayer = NULL; PLAYER* pPlayer = NULL;
if (rxId >= kChannelPlayer0 && rxId <= kChannelPlayer7) { if (playerRXRngIsFine(rxId)) {
if ((pPlayer = getPlayerById((kChannelPlayer0 - kChannelPlayer7) + kMaxPlayers)) != NULL) if ((pPlayer = getPlayerById((kChannelPlayer0 - kChannelPlayer7) + kMaxPlayers)) != NULL)
trMessageSprite(pPlayer->nSprite, event); trMessageSprite(pPlayer->nSprite, event);
} else if (rxId == kChannelAllPlayers) { } else if (rxId == kChannelAllPlayers) {
@ -439,6 +440,9 @@ void evSend(int nIndex, int nType, int rxId, COMMAND_ID command, short causedBy)
if ((pPlayer = getPlayerById(i)) != NULL) if ((pPlayer = getPlayerById(i)) != NULL)
trMessageSprite(pPlayer->nSprite, event); trMessageSprite(pPlayer->nSprite, event);
} }
// send command on sprite which create the event sequence
} else if (rxId == kChannelEventCauser && spriRangeIsFine(event.causedBy)) {
trMessageSprite(event.causedBy, event);
} }
} }

View file

@ -40,9 +40,8 @@ kChannelLevelStartCoop,
kChannelLevelStartTeamsOnly, kChannelLevelStartTeamsOnly,
kChannelPlayerDeathTeamA = 15, kChannelPlayerDeathTeamA = 15,
kChannelPlayerDeathTeamB, kChannelPlayerDeathTeamB,
// by NoOne: RX channels of players to send commands on
///////////////////////////// /////////////////////////////
// channels of players to send commands on
kChannelPlayer0 = 30, kChannelPlayer0 = 30,
kChannelPlayer1, kChannelPlayer1,
kChannelPlayer2, kChannelPlayer2,
@ -52,10 +51,11 @@ kChannelPlayer5,
kChannelPlayer6, kChannelPlayer6,
kChannelPlayer7, kChannelPlayer7,
kChannelAllPlayers = kChannelPlayer0 + kMaxPlayers, kChannelAllPlayers = kChannelPlayer0 + kMaxPlayers,
// channel of event causer
kChannelEventCauser = 50,
// map requires modern features to work properly
kChannelMapModernize = 60,
///////////////////////////// /////////////////////////////
kChannelMapModernize = 60, // map requires modern features to work properly
kChannelTeamAFlagCaptured = 80, kChannelTeamAFlagCaptured = 80,
kChannelTeamBFlagCaptured, kChannelTeamBFlagCaptured,
kChannelRemoteBomb0 = 90, kChannelRemoteBomb0 = 90,
@ -79,44 +79,44 @@ extern RXBUCKET rxBucket[];
extern unsigned short bucketHead[]; extern unsigned short bucketHead[];
enum COMMAND_ID { enum COMMAND_ID {
kCmdOff = 0, kCmdOff = 0,
kCmdOn = 1, kCmdOn = 1,
kCmdState = 2, kCmdState = 2,
kCmdToggle = 3, kCmdToggle = 3,
kCmdNotState = 4, kCmdNotState = 4,
kCmdLink = 5, kCmdLink = 5,
kCmdLock = 6, kCmdLock = 6,
kCmdUnlock = 7, kCmdUnlock = 7,
kCmdToggleLock = 8, kCmdToggleLock = 8,
kCmdStopOff = 9, kCmdStopOff = 9,
kCmdStopOn = 10, kCmdStopOn = 10,
kCmdStopNext = 11, kCmdStopNext = 11,
kCmdCounterSector = 12, kCmdCounterSector = 12,
kCmdCallback = 20, kCmdCallback = 20,
kCmdRepeat = 21, kCmdRepeat = 21,
kCmdSpritePush = 30, kCmdSpritePush = 30,
kCmdSpriteImpact = 31, kCmdSpriteImpact = 31,
kCmdSpritePickup = 32, kCmdSpritePickup = 32,
kCmdSpriteTouch = 33, kCmdSpriteTouch = 33,
kCmdSpriteSight = 34, kCmdSpriteSight = 34,
kCmdSpriteProximity = 35, kCmdSpriteProximity = 35,
kCmdSpriteExplode = 36, kCmdSpriteExplode = 36,
kCmdSectorPush = 40, kCmdSectorPush = 40,
kCmdSectorImpact = 41, kCmdSectorImpact = 41,
kCmdSectorEnter = 42, kCmdSectorEnter = 42,
kCmdSectorExit = 43, kCmdSectorExit = 43,
kCmdWallPush = 50, kCmdWallPush = 50,
kCmdWallImpact = 51, kCmdWallImpact = 51,
kCmdWallTouch = 52, kCmdWallTouch = 52,
kCmdModernUse = 53, // used by most of modern types kCmdModernUse = 53, // used by most of modern types
kCmdNumberic = 64, // 64: 0, 65: 1 and so on up to 255 kCmdNumberic = 64, // 64: 0, 65: 1 and so on up to 255
kCmdModernFeaturesEnable = 100, // must be in object with kChannelMapModernize RX / TX kCmdModernFeaturesEnable = 100, // must be in object with kChannelMapModernize RX / TX
kCmdModernFeaturesDisable = 200, // must be in object with kChannelMapModernize RX / TX kCmdModernFeaturesDisable = 200, // must be in object with kChannelMapModernize RX / TX
kCmdNumbericMax = 255, kCmdNumbericMax = 255,
}; };
inline bool playerRXRngIsFine(int rx) { inline bool playerRXRngIsFine(int rx) {

View file

@ -357,7 +357,7 @@ void levelEndLevel(int arg)
} }
} }
// By NoOne: this function can be called via sending numbered command to TX kGDXChannelEndLevel // By NoOne: this function can be called via sending numbered command to TX kChannelModernEndLevelCustom
// This allows to set custom next level instead of taking it from INI file. // This allows to set custom next level instead of taking it from INI file.
void levelEndLevelCustom(int nLevel) { void levelEndLevelCustom(int nLevel) {

View file

@ -483,23 +483,45 @@ QAV* qavSceneLoad(int qavId) {
return pQav; return pQav;
} }
void qavSceneDraw(PLAYER* pPlayer, int a2, int a3, int a4, int a5) { void qavSceneDraw(PLAYER* pPlayer, int a2, int a3, int a4, int a5) {
if (pPlayer == NULL || pPlayer->sceneQav == -1) return; if (pPlayer == NULL || pPlayer->sceneQav == -1) return;
QAVSCENE* pQavScene = &gPlayerCtrl[pPlayer->nPlayer].qavScene; QAVSCENE* pQavScene = &gPlayerCtrl[pPlayer->nPlayer].qavScene;
spritetype* pSprite = &sprite[pQavScene->index];
if (pQavScene->qavResrc != NULL) { if (pQavScene->qavResrc != NULL) {
QAV* pQAV = pQavScene->qavResrc; QAV* pQAV = pQavScene->qavResrc;
int v4 = (pPlayer->weaponTimer == 0) ? (int)totalclock % pQAV->at10 : pQAV->at10 - pPlayer->weaponTimer; int v4 = (pPlayer->weaponTimer == 0) ? (int)totalclock % pQAV->at10 : pQAV->at10 - pPlayer->weaponTimer;
pQAV->x = a3; pQAV->y = a4; int flags = 2; int flags = 2; int nInv = powerupCheck(pPlayer, kPwUpShadowCloak);
int nInv = powerupCheck(pPlayer, kPwUpShadowCloak);
if (nInv >= 120 * 8 || (nInv != 0 && ((int)totalclock & 32))) { if (nInv >= 120 * 8 || (nInv != 0 && ((int)totalclock & 32))) {
a2 = -128; a2 = -128; flags |= 1;
flags |= 1;
} }
// draw as weapon
if (!(pSprite->flags & kModernTypeFlag1)) {
pQAV->x = a3; pQAV->y = a4;
pQAV->Draw(v4, flags, a2, a5); pQAV->Draw(v4, flags, a2, a5);
// draw fullscreen (currently 4:3 only)
} else {
int wx1 = windowxy1.x, wy1 = windowxy1.y, wx2 = windowxy2.x, wy2 = windowxy2.y;
windowxy2.x = xdim - 1; windowxy2.y = ydim - 1;
windowxy1.x = windowxy1.y = 0;
pQAV->Draw(v4, flags, a2, a5);
windowxy1.x = wx1; windowxy1.y = wy1;
windowxy2.x = wx2; windowxy2.y = wy2;
}
} }
} }

View file

@ -64,7 +64,7 @@ struct PLAYER {
DUDEINFO *pDudeInfo; DUDEINFO *pDudeInfo;
GINPUT input; GINPUT input;
//short input; // INPUT //short input; // INPUT
//char at10; // forward //char moveFunc; // forward
//short at11; // turn //short at11; // turn
//char hearDist; // strafe //char hearDist; // strafe
//int bobV; // buttonFlags //int bobV; // buttonFlags
@ -216,11 +216,15 @@ struct POWERUPINFO {
int maxTime; int maxTime;
}; };
#define kQavSceneStackSize 16
// by NoOne: this one stores qavs anims that can be played by trigger // by NoOne: this one stores qavs anims that can be played by trigger
struct QAVSCENE { struct QAVSCENE {
short index = -1; // index of sprite which triggered qav scene short index = -1; // index of sprite which triggered qav scene
QAV* qavResrc = NULL; QAV* qavResrc = NULL;
short causedBy = -1; short causedBy = -1;
// TO-DO: Stack of animations which allows to pop and push (restoring previous animation instead of weapon once current animation is played)
}; };
// by NoOne: this one for controlling the player using triggers (movement speed, jumps and other stuff) // by NoOne: this one for controlling the player using triggers (movement speed, jumps and other stuff)

View file

@ -56,7 +56,7 @@ struct Seq {
short at8; short at8;
short ata; short ata;
int atc; int atc;
SEQFRAME frames[1]; // at10 SEQFRAME frames[1];
void Preload(void); void Preload(void);
void Precache(void); void Precache(void);
}; };

View file

@ -42,28 +42,6 @@ POINT2D earL, earR, earL0, earR0; // Ear position
VECTOR2D earVL, earVR; // Ear velocity ? VECTOR2D earVL, earVR; // Ear velocity ?
int lPhase, rPhase, lVol, rVol, lPitch, rPitch; int lPhase, rPhase, lVol, rVol, lPitch, rPitch;
struct BONKLE
{
int at0;
int at4;
DICTNODE *at8;
int atc;
spritetype *at10;
int at14;
int at18;
int at1c;
POINT3D at20;
POINT3D at2c;
//int at20;
//int at24;
//int at28;
//int at2c;
//int at30;
//int at34;
int at38;
int at3c;
};
BONKLE Bonkle[256]; BONKLE Bonkle[256];
BONKLE *BonkleCache[256]; BONKLE *BonkleCache[256];

View file

@ -25,6 +25,31 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
BEGIN_BLD_NS BEGIN_BLD_NS
struct BONKLE
{
int at0;
int at4;
DICTNODE* at8;
int atc;
spritetype* at10;
int at14;
int at18;
int at1c;
POINT3D at20;
POINT3D at2c;
//int at20;
//int at24;
//int at28;
//int at2c;
//int at30;
//int at34;
int at38;
int at3c;
};
extern BONKLE Bonkle[256];
extern BONKLE* BonkleCache[256];
void sfxInit(void); void sfxInit(void);
void sfxTerm(void); void sfxTerm(void);
void sfxPlay3DSound(int x, int y, int z, int soundId, int nSector); void sfxPlay3DSound(int x, int y, int z, int soundId, int nSector);

View file

@ -863,29 +863,30 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
} }
return; return;
case kModernPlayerControl: // WIP case kModernPlayerControl: // WIP
PLAYER* pPlayer = NULL; int nPlayer = pXSprite->data1; PLAYER* pPlayer = NULL; int nPlayer = pXSprite->data1; int oldCmd = -1;
if (pXSprite->data1 == 0 && spriRangeIsFine(event.causedBy)) if (pXSprite->data1 == 0 && spriRangeIsFine(event.causedBy))
nPlayer = sprite[event.causedBy].type; nPlayer = sprite[event.causedBy].type;
if ((pPlayer = getPlayerById(nPlayer)) == NULL || pPlayer->pXSprite->health <= 0) if ((pPlayer = getPlayerById(nPlayer)) == NULL || pPlayer->pXSprite->health <= 0) return;
return; else if (pXSprite->command < kCmdNumberic + 3 && pXSprite->command > kCmdNumberic + 4
&& !modernTypeSetSpriteState(nSprite, pXSprite, pXSprite->state ^ 1, event.causedBy)) return;
TRPLAYERCTRL* pCtrl = pCtrl = &gPlayerCtrl[pPlayer->nPlayer]; TRPLAYERCTRL* pCtrl = pCtrl = &gPlayerCtrl[pPlayer->nPlayer];
if (event.cmd >= kCmdNumberic) { if (event.cmd >= kCmdNumberic) {
switch (event.cmd) { switch (event.cmd) {
case kCmdNumberic + 3:// start playing qav scene case kCmdNumberic + 3:// start playing qav scene
viewSetSystemMessage("START QAV %d, %d", pXSprite->rxID, pXSprite->txID);
if (pCtrl->qavScene.index != nSprite || pXSprite->Interrutable) if (pCtrl->qavScene.index != nSprite || pXSprite->Interrutable)
trPlayerCtrlStartScene(pXSprite, pPlayer, event.causedBy); trPlayerCtrlStartScene(pXSprite, pPlayer, event.causedBy);
break; return;
case kCmdNumberic + 4: // stop playing qav scene case kCmdNumberic + 4: // stop playing qav scene
viewSetSystemMessage("STOP QAV", gPlayerCtrl[pPlayer->nPlayer].qavScene.index); if (pCtrl->qavScene.index == nSprite || event.type != 3 || sprite[event.index].type != kModernPlayerControl)
if (pCtrl->qavScene.index == nSprite)
trPlayerCtrlStopScene(pXSprite, pPlayer); trPlayerCtrlStopScene(pXSprite, pPlayer);
return;
default:
oldCmd = pXSprite->command;
pXSprite->command = event.cmd; // convert event command to current sprite command
break; break;
} }
return;
} }
/// !!! COMMANDS OF THE CURRENT SPRITE, NOT OF THE EVENT !!! /// /// !!! COMMANDS OF THE CURRENT SPRITE, NOT OF THE EVENT !!! ///
@ -923,7 +924,8 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
gPosture[i][a].frontAccel = gPosture[i][a].sideAccel = gPosture[i][a].backAccel = ClipRange(mulscale8(defSpeed, speed), 0, 65535); gPosture[i][a].frontAccel = gPosture[i][a].sideAccel = gPosture[i][a].backAccel = ClipRange(mulscale8(defSpeed, speed), 0, 65535);
} }
} }
viewSetSystemMessage("MOVEMENT: %d %d %d", pXSprite->rxID,pSprite->index, gPosture[0][0].frontAccel);
//viewSetSystemMessage("MOVEMENT: %d %d %d", pXSprite->rxID,pSprite->index, gPosture[0][0].frontAccel);
} }
// player jump height (for all players ATM) // player jump height (for all players ATM)
@ -941,7 +943,7 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
} }
} }
} }
viewSetSystemMessage("JUMPING: %d", gPosture[0][0].normalJumpZ); //viewSetSystemMessage("JUMPING: %d", gPosture[0][0].normalJumpZ);
} }
break; break;
@ -950,7 +952,7 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
if (pXSprite->data3 < 0) break; if (pXSprite->data3 < 0) break;
switch (pXSprite->data2) { switch (pXSprite->data2) {
case 1: // tilting case 1: // tilting
pPlayer->tiltEffect = pXSprite->data3; pPlayer->tiltEffect = ClipRange(pXSprite->data3, 0, 220);
break; break;
case 2: // pain case 2: // pain
pPlayer->painEffect = pXSprite->data3; pPlayer->painEffect = pXSprite->data3;
@ -987,27 +989,25 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
case kCmdNumberic + 5: // 69 case kCmdNumberic + 5: // 69
// set player sprite and look angles // set player sprite and look angles
if (pXSprite->data2 == 0) { if (pXSprite->data4 == 0) {
// look angle // look angle
if (valueIsBetween(pXSprite->data3, -128, 128)) { if (valueIsBetween(pXSprite->data2, -128, 128)) {
CONSTEXPR int upAngle = 289; CONSTEXPR int downAngle = -347; CONSTEXPR int upAngle = 289; CONSTEXPR int downAngle = -347;
CONSTEXPR double lookStepUp = 4.0 * upAngle / 60.0; CONSTEXPR double lookStepUp = 4.0 * upAngle / 60.0;
CONSTEXPR double lookStepDown = -4.0 * downAngle / 60.0; CONSTEXPR double lookStepDown = -4.0 * downAngle / 60.0;
int look = pXSprite->data3 << 5; int look = pXSprite->data2 << 5;
if (look > 0) pPlayer->q16look = fix16_min(mulscale8(F16(lookStepUp), look), F16(upAngle)); if (look > 0) pPlayer->q16look = fix16_min(mulscale8(F16(lookStepUp), look), F16(upAngle));
else if (look < 0) pPlayer->q16look = -fix16_max(mulscale8(F16(lookStepDown), abs(look)), F16(downAngle)); else if (look < 0) pPlayer->q16look = -fix16_max(mulscale8(F16(lookStepDown), abs(look)), F16(downAngle));
else pPlayer->q16look = 0; else pPlayer->q16look = 0;
} }
// angle // angle
if ((pSprite->flags & kModernTypeFlag1) && valueIsBetween(pXSprite->data4, 0, kAng180)) // TO-DO: if tx > 0, take a look on TX ID sprite
pPlayer->pSprite->ang = pXSprite->data4; if (pXSprite->data3 == 1) pPlayer->pSprite->ang = pXSprite->data3;
else if (pXSprite->data4 == 1) else if (valueIsBetween(pXSprite->data3, 0, kAng180))
pPlayer->pSprite->ang = pSprite->ang; pPlayer->pSprite->ang = pXSprite->data3;
} }
//viewSetSystemMessage("ANGLE: %d, SLOPE: %d", pPlayer->pSprite->ang, pPlayer->q16look); //viewSetSystemMessage("ANGLE: %d, SLOPE: %d", pPlayer->pSprite->ang, pPlayer->q16look);
break; break;
@ -1017,15 +1017,16 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
switch (pXSprite->data2) { switch (pXSprite->data2) {
// erase all // erase all
case 0: case 0:
// erase all weapons except pitchfork // erase weapons
case 1: case 1:
// erase all
if (pXSprite->data3 <= 0) {
WeaponLower(pPlayer); WeaponLower(pPlayer);
for (int i = 0; i < 14; i++) { for (int i = 0; i < 14; i++) {
pPlayer->hasWeapon[i] = false; pPlayer->hasWeapon[i] = false;
// also erase ammo // also erase ammo
if (i < 12 && pXSprite->data3 == 1) if (i < 12) pPlayer->ammoCount[i] = 0;
pPlayer->ammoCount[i] = 0;
} }
pPlayer->hasWeapon[1] = true; pPlayer->hasWeapon[1] = true;
@ -1033,6 +1034,11 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
pPlayer->nextWeapon = 1; pPlayer->nextWeapon = 1;
WeaponRaise(pPlayer); WeaponRaise(pPlayer);
// erase just specified
} else {
}
if (pXSprite->data2) break; if (pXSprite->data2) break;
// erase all armor // erase all armor
case 2: case 2:
@ -1065,11 +1071,11 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
if (pXSprite->data2 == 1) { if (pXSprite->data2 == 1) {
pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + pWeaponData->count, gAmmoInfo[nAmmoType].max); pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + pWeaponData->count, gAmmoInfo[nAmmoType].max);
} else { } else {
pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + pXSprite->data3, gAmmoInfo[nAmmoType].max); pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + pXSprite->data4, gAmmoInfo[nAmmoType].max);
break; break;
} }
pPlayer->hasWeapon[pXSprite->data2] = true; pPlayer->hasWeapon[pXSprite->data3] = true;
if (pXSprite->data4 == 0) { // switch on it if (pXSprite->data4 == 0) { // switch on it
if (pPlayer->sceneQav >= 0) { if (pPlayer->sceneQav >= 0) {
@ -1085,7 +1091,19 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
break; break;
} }
break; break;
case kCmdNumberic + 8: // 72
// use inventory item
if (pXSprite->data2 > 0 && pXSprite->data2 <= 5) {
packUseItem(pPlayer, pXSprite->data2 - 1);
// force remove after use
if (pXSprite->data4 == 1)
pPlayer->packSlots[0].curAmount = pPlayer->packSlots[0].curAmount = 0;
} }
break;
}
if (oldCmd > -1) pXSprite->command = oldCmd;
return; return;
} }
} }
@ -1549,10 +1567,6 @@ void useObjResizer(XSPRITE* pXSource, short objType, int objIndex) {
// for sprites // for sprites
case 3: case 3:
/*PLAYER* pPlayer = NULL;
if (playerRXRngIsFine(pXSource->txID) && (pPlayer = getPlayerById((kChannelPlayer0 - kChannelPlayer7) + kMaxPlayers)) != NULL)
objIndex = pPlayer->nSprite;*/
// resize by seq scaling // resize by seq scaling
if (sprite[pXSource->reference].flags & kModernTypeFlag1) { if (sprite[pXSource->reference].flags & kModernTypeFlag1) {
if (valueIsBetween(pXSource->data1, -255, 32767)) { if (valueIsBetween(pXSource->data1, -255, 32767)) {
@ -1565,9 +1579,11 @@ void useObjResizer(XSPRITE* pXSource, short objType, int objIndex) {
switch (sprite[objIndex].type) { switch (sprite[objIndex].type) {
case kDudeModernCustom: case kDudeModernCustom:
case kDudeModernCustomBurning: case kDudeModernCustomBurning:
gGenDudeExtra[objIndex].updReq[kGenDudePropertySpriteSize] = true;
gGenDudeExtra[objIndex].updReq[kGenDudePropertyAttack] = true; gGenDudeExtra[objIndex].updReq[kGenDudePropertyAttack] = true;
gGenDudeExtra[objIndex].updReq[kGenDudePropertyMass] = true; gGenDudeExtra[objIndex].updReq[kGenDudePropertyMass] = true;
gGenDudeExtra[objIndex].updReq[kGenDudePropertyDamage] = true; gGenDudeExtra[objIndex].updReq[kGenDudePropertyDmgScale] = true;
evPost(objIndex, 3, kGenDudeUpdTimeRate, kCallbackGenDudeUpdate, -1);
break; break;
} }
} }
@ -1583,7 +1599,6 @@ void useObjResizer(XSPRITE* pXSource, short objType, int objIndex) {
} }
if (valueIsBetween(pXSource->data3, -1, 32767)) if (valueIsBetween(pXSource->data3, -1, 32767))
sprite[objIndex].xoffset = ClipRange(pXSource->data3, 0, 255); sprite[objIndex].xoffset = ClipRange(pXSource->data3, 0, 255);
@ -1876,7 +1891,12 @@ void useTeleportTarget(XSPRITE* pXSource, spritetype* pSprite) {
if (pXSector != NULL && pXSector->Underwater) xsprite[pSprite->extra].medium = kMediumWater; if (pXSector != NULL && pXSector->Underwater) xsprite[pSprite->extra].medium = kMediumWater;
else xsprite[pSprite->extra].medium = kMediumNormal; else xsprite[pSprite->extra].medium = kMediumNormal;
if (pXSource->data2 == 1) pSprite->ang = pSource->ang; if (pXSource->data2 == 1) {
pSprite->ang = pSource->ang;
if (IsDudeSprite(pSprite) && xspriRangeIsFine(pSprite->index))
xsprite[pSprite->extra].goalAng = pSprite->ang;
}
if (pXSource->data3 == 1) if (pXSource->data3 == 1)
xvel[pSprite->xvel] = yvel[pSprite->xvel] = zvel[pSprite->xvel] = 0; xvel[pSprite->xvel] = yvel[pSprite->xvel] = zvel[pSprite->xvel] = 0;
@ -2006,11 +2026,21 @@ void useSectorWindGen(XSPRITE* pXSource, sectortype* pSector) {
} }
} }
void useSpriteDamager(XSPRITE* pXSource, spritetype* pSprite) { void useSpriteDamager(XSPRITE* pXSource, spritetype* pSprite) {
if (pSprite != NULL) {
int dmgType = (pXSource->data2 == 7) ? Random(6) : ClipRange(pXSource->data2, 0, 6); spritetype* pSource = &sprite[pXSource->reference];
if (pSprite != NULL && xspriIsFine(pSprite->index)) {
int dmg = (pXSource->data3 == 0) ? 65535 : ClipRange(pXSource->data3, 1, 65535); int dmg = (pXSource->data3 == 0) ? 65535 : ClipRange(pXSource->data3, 1, 65535);
actDamageSprite(pSprite->index, pSprite, (DAMAGE_TYPE)dmgType, dmg); int dmgType = ClipRange(pXSource->data2, 0, 6);
if (pXSource->data2 == -1 && IsDudeSprite(pSprite)) {
xsprite[pSprite->extra].health = ClipLow(xsprite[pSprite->extra].health - dmg, 0);
if (xsprite[pSprite->extra].health == 0)
actKillDude(pSource->index, pSprite, (DAMAGE_TYPE)0, 65535);
}
else actDamageSprite(pSource->index, pSprite, (DAMAGE_TYPE)dmgType, dmg);
} }
} }
@ -4206,7 +4236,22 @@ int getDataFieldOfObject(int objType, int objIndex, int dataIndex) {
bool setDataValueOfObject(int objType, int objIndex, int dataIndex, int value, int causedBy) { bool setDataValueOfObject(int objType, int objIndex, int dataIndex, int value, int causedBy) {
switch (objType) { switch (objType) {
case 3: case 3: {
XSPRITE* pXSprite = &xsprite[sprite[objIndex].extra];
// exceptions
if (IsDudeSprite(&sprite[objIndex]) && pXSprite->health <= 0) return true;
/*switch (sprite[objIndex].type) {
case kThingBloodBits:
case kThingBloodChunks:
case kThingZombieHead:
case kThingObjectGib:
case kThingObjectExplode:
if (pXSprite->data1 > 0 || pXSprite->data2 > 0 || pXSprite->data3 > 0 || pXSprite->data4 > 0) return true;
break;
}*/
switch (dataIndex) { switch (dataIndex) {
case 1: case 1:
xsprite[sprite[objIndex].extra].data1 = value; xsprite[sprite[objIndex].extra].data1 = value;
@ -4218,8 +4263,8 @@ bool setDataValueOfObject(int objType, int objIndex, int dataIndex, int value, i
case kDudeModernCustom: case kDudeModernCustom:
case kDudeModernCustomBurning: case kDudeModernCustomBurning:
gGenDudeExtra[objIndex].updReq[kGenDudePropertyWeapon] = true; gGenDudeExtra[objIndex].updReq[kGenDudePropertyWeapon] = true;
gGenDudeExtra[objIndex].updReq[kGenDudePropertyMelee] = true; gGenDudeExtra[objIndex].updReq[kGenDudePropertyDmgScale] = true;
gGenDudeExtra[objIndex].updReq[kGenDudePropertyDamage] = true; evPost(objIndex, 3, kGenDudeUpdTimeRate, kCallbackGenDudeUpdate, causedBy);
break; break;
} }
return true; return true;
@ -4228,10 +4273,12 @@ bool setDataValueOfObject(int objType, int objIndex, int dataIndex, int value, i
switch (sprite[objIndex].type) { switch (sprite[objIndex].type) {
case kDudeModernCustom: case kDudeModernCustom:
case kDudeModernCustomBurning: case kDudeModernCustomBurning:
gGenDudeExtra[objIndex].updReq[kGenDudePropertySpriteSize] = true;
gGenDudeExtra[objIndex].updReq[kGenDudePropertyMass] = true; gGenDudeExtra[objIndex].updReq[kGenDudePropertyMass] = true;
gGenDudeExtra[objIndex].updReq[kGenDudePropertyDamage] = true; gGenDudeExtra[objIndex].updReq[kGenDudePropertyDmgScale] = true;
gGenDudeExtra[objIndex].updReq[kGenDudePropertyStates] = true; gGenDudeExtra[objIndex].updReq[kGenDudePropertyStates] = true;
gGenDudeExtra[objIndex].updReq[kGenDudePropertyAttack] = true; gGenDudeExtra[objIndex].updReq[kGenDudePropertyAttack] = true;
evPost(objIndex, 3, kGenDudeUpdTimeRate, kCallbackGenDudeUpdate, causedBy);
break; break;
} }
return true; return true;
@ -4250,6 +4297,7 @@ bool setDataValueOfObject(int objType, int objIndex, int dataIndex, int value, i
default: default:
return false; return false;
} }
}
case 0: case 0:
xsector[sector[objIndex].extra].data = value; xsector[sector[objIndex].extra].data = value;
return true; return true;