mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-28 01:40:41 +00:00
- Player control: more strict rules for copying properties of xsprite
- Fix for custom health when respawning enemy - Fix for custom dude when respawning it - Conditions: added way to refresh sprite index in tracking conditions # Conflicts: # source/blood/src/actor.cpp # source/blood/src/aiunicult.cpp # source/blood/src/aiunicult.h # source/blood/src/dude.cpp # source/blood/src/dude.h
This commit is contained in:
parent
8b0da35cb8
commit
64de30209b
11 changed files with 241 additions and 122 deletions
|
@ -2469,7 +2469,7 @@ void actInit(bool bSaveLoad) {
|
|||
nnExtInitModernStuff(bSaveLoad);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
for (int nSprite = headspritestat[kStatItem]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
|
||||
switch (sprite[nSprite].type) {
|
||||
case kItemWeaponVoodooDoll:
|
||||
|
@ -2587,15 +2587,7 @@ void actInit(bool bSaveLoad) {
|
|||
#endif
|
||||
|
||||
xvel[nSprite] = yvel[nSprite] = zvel[nSprite] = 0;
|
||||
|
||||
#ifdef NOONE_EXTENSIONS
|
||||
// add a way to set custom hp for every enemy - should work only if map just started and not loaded.
|
||||
if (!gModernMap || pXSprite->data4 <= 0) pXSprite->health = dudeInfo[nType].startHealth << 4;
|
||||
else pXSprite->health = ClipRange(pXSprite->data4 << 4, 1, 65535);
|
||||
#else
|
||||
pXSprite->health = dudeInfo[nType].startHealth << 4;
|
||||
#endif
|
||||
|
||||
pXSprite->health = dudeGetStartHp(pSprite);
|
||||
}
|
||||
|
||||
if (gSysRes.Lookup(seqStartId, "SEQ")) seqSpawn(seqStartId, 3, pSprite->extra);
|
||||
|
@ -3239,26 +3231,28 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
|
|||
seqSpawn(dudeInfo[nType].seqStartID+15, 3, nXSprite, nDudeToGibClient2);
|
||||
break;
|
||||
#ifdef NOONE_EXTENSIONS
|
||||
case kDudeModernCustom:
|
||||
case kDudeModernCustom: {
|
||||
playGenDudeSound(pSprite, kGenDudeSndDeathNormal);
|
||||
int dudeToGib = (actCheckRespawn(pSprite)) ? -1 : ((nSeq == 3) ? nDudeToGibClient2 : nDudeToGibClient1);
|
||||
if (nSeq == 3) {
|
||||
|
||||
|
||||
GENDUDEEXTRA* pExtra = genDudeExtra(pSprite);
|
||||
if (pExtra->availDeaths[kDmgBurn] == 3) seqSpawn((15 + Random(2)) + pXSprite->data2, 3, nXSprite, nDudeToGibClient2);
|
||||
else if (pExtra->availDeaths[kDmgBurn] == 2) seqSpawn(16 + 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 seqSpawn(1 + pXSprite->data2, 3, nXSprite, nDudeToGibClient2);
|
||||
if (pExtra->availDeaths[kDmgBurn] == 3) seqSpawn((15 + Random(2)) + pXSprite->data2, 3, nXSprite, dudeToGib);
|
||||
else if (pExtra->availDeaths[kDmgBurn] == 2) seqSpawn(16 + pXSprite->data2, 3, nXSprite, dudeToGib);
|
||||
else if (pExtra->availDeaths[kDmgBurn] == 1) seqSpawn(15 + pXSprite->data2, 3, nXSprite, dudeToGib);
|
||||
else if (gSysRes.Lookup(pXSprite->data2 + nSeq, "SEQ"))seqSpawn(nSeq + pXSprite->data2, 3, nXSprite, dudeToGib);
|
||||
else seqSpawn(1 + pXSprite->data2, 3, nXSprite, dudeToGib);
|
||||
|
||||
} else {
|
||||
seqSpawn(nSeq + pXSprite->data2, 3, nXSprite, nDudeToGibClient1);
|
||||
seqSpawn(nSeq + pXSprite->data2, 3, nXSprite, dudeToGib);
|
||||
}
|
||||
genDudePostDeath(pSprite, damageType, damage);
|
||||
return;
|
||||
|
||||
pXSprite->txID = 0; // to avoid second trigger.
|
||||
break;
|
||||
|
||||
}
|
||||
case kDudeModernCustomBurning: {
|
||||
playGenDudeSound(pSprite, kGenDudeSndDeathExplode);
|
||||
int dudeToGib = (actCheckRespawn(pSprite)) ? -1 : nDudeToGibClient1;
|
||||
damageType = DAMAGE_TYPE_3;
|
||||
|
||||
if (Chance(0x4000)) {
|
||||
|
@ -3270,11 +3264,12 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
|
|||
}
|
||||
|
||||
GENDUDEEXTRA* pExtra = genDudeExtra(pSprite);
|
||||
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);
|
||||
else if (pExtra->availDeaths[kDmgBurn] == 1) seqSpawn(15 + pXSprite->data2, 3, nXSprite, nDudeToGibClient1);
|
||||
else seqSpawn(1 + pXSprite->data2, 3, nXSprite, nDudeToGibClient1);
|
||||
break;
|
||||
if (pExtra->availDeaths[kDmgBurn] == 3) seqSpawn((15 + Random(2)) + pXSprite->data2, 3, nXSprite, dudeToGib);
|
||||
else if (pExtra->availDeaths[kDmgBurn] == 2) seqSpawn(16 + pXSprite->data2, 3, nXSprite, dudeToGib);
|
||||
else if (pExtra->availDeaths[kDmgBurn] == 1) seqSpawn(15 + pXSprite->data2, 3, nXSprite, dudeToGib);
|
||||
else seqSpawn(1 + pXSprite->data2, 3, nXSprite, dudeToGib);
|
||||
genDudePostDeath(pSprite, damageType, damage);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
case kDudeBurningZombieAxe:
|
||||
|
|
|
@ -1532,20 +1532,17 @@ void aiInitSprite(spritetype *pSprite)
|
|||
DUDEEXTRA *pDudeExtra = &gDudeExtra[pSprite->extra];
|
||||
pDudeExtra->at4 = 0;
|
||||
pDudeExtra->at0 = 0;
|
||||
|
||||
switch (pSprite->type) {
|
||||
#ifdef NOONE_EXTENSIONS
|
||||
case kDudeModernCustom: {
|
||||
DUDEEXTRA_at6_u1* pDudeExtraE = &gDudeExtra[nXSprite].at6.u1;
|
||||
pDudeExtraE->at8 = pDudeExtraE->at0 = 0;
|
||||
aiGenDudeNewState(pSprite, &genDudeIdleL);
|
||||
genDudePrepare(pSprite);
|
||||
break;
|
||||
}
|
||||
#ifdef NOONE_EXTENSIONS
|
||||
case kDudeModernCustom:
|
||||
aiGenDudeInitSprite(pSprite, pXSprite);
|
||||
genDudePrepare(pSprite, kGenDudePropertyAll);
|
||||
return;
|
||||
case kDudeModernCustomBurning:
|
||||
aiGenDudeNewState(pSprite, &genDudeBurnGoto);
|
||||
pXSprite->burnTime = 1200;
|
||||
break;
|
||||
#endif
|
||||
aiGenDudeInitSprite(pSprite, pXSprite);
|
||||
return;
|
||||
#endif
|
||||
case kDudeCultistTommy:
|
||||
case kDudeCultistShotgun:
|
||||
case kDudeCultistTesla:
|
||||
|
|
|
@ -53,6 +53,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include "tile.h"
|
||||
#include "sound/s_soundinternal.h"
|
||||
|
||||
#include "gib.h"
|
||||
#include "aiburn.h"
|
||||
|
||||
BEGIN_BLD_NS
|
||||
static void genDudeAttack1(int, int);
|
||||
static void punchCallback(int, int);
|
||||
|
@ -174,7 +177,6 @@ bool genDudeAdjustSlope(spritetype* pSprite, XSPRITE* pXSprite, int dist, int we
|
|||
}
|
||||
|
||||
GENDUDEEXTRA* genDudeExtra(spritetype* pGenDude) {
|
||||
dassert(spriRangeIsFine(pGenDude->index));
|
||||
return &gGenDudeExtra[pGenDude->index];
|
||||
}
|
||||
|
||||
|
@ -1254,14 +1256,9 @@ XSPRITE* getNextIncarnation(XSPRITE* pXSprite) {
|
|||
if (rxBucket[i].type != 3 || rxBucket[i].index == pXSprite->reference)
|
||||
continue;
|
||||
|
||||
switch (sprite[rxBucket[i].index].statnum) {
|
||||
case kStatDude:
|
||||
case kStatInactive: // inactive (ambush) dudes
|
||||
if (xsprite[sprite[rxBucket[i].index].extra].health > 0)
|
||||
if (sprite[rxBucket[i].index].statnum == kStatInactive)
|
||||
return &xsprite[sprite[rxBucket[i].index].extra];
|
||||
}
|
||||
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1650,9 +1647,7 @@ spritetype* genDudeSpawn(spritetype* pSprite, int nDist) {
|
|||
if (pSource->clipdist > 0) pDude->clipdist = pSource->clipdist;
|
||||
|
||||
// inherit custom hp settings
|
||||
if (pXSource->data4 <= 0) pXDude->health = dudeInfo[nType - kDudeBase].startHealth << 4;
|
||||
else pXDude->health = ClipRange(pXSource->data4 << 4, 1, 65535);
|
||||
|
||||
pXDude->health = dudeGetStartHp(pDude);
|
||||
|
||||
if (pSource->flags & kModernTypeFlag1) {
|
||||
switch (pSource->type) {
|
||||
|
@ -1720,7 +1715,7 @@ void genDudeTransform(spritetype* pSprite) {
|
|||
// trigger dude death before transform
|
||||
trTriggerSprite(pSprite->index, pXSprite, kCmdOff);
|
||||
|
||||
pSprite->type = pIncarnation->type;
|
||||
pSprite->type = pSprite->inittype = pIncarnation->type;
|
||||
pSprite->flags = pIncarnation->flags;
|
||||
pSprite->pal = pIncarnation->pal;
|
||||
pSprite->shade = pIncarnation->shade;
|
||||
|
@ -1735,17 +1730,18 @@ void genDudeTransform(spritetype* pSprite) {
|
|||
pXSprite->busyTime = pXIncarnation->busyTime;
|
||||
pXSprite->waitTime = pXIncarnation->waitTime;
|
||||
|
||||
// inherit respawn properties
|
||||
pXSprite->respawn = pXIncarnation->respawn;
|
||||
pXSprite->respawnPending = pXIncarnation->respawnPending;
|
||||
|
||||
pXSprite->burnTime = 0;
|
||||
pXSprite->burnSource = -1;
|
||||
|
||||
pXSprite->data1 = pXIncarnation->data1;
|
||||
pXSprite->data2 = pXIncarnation->data2;
|
||||
|
||||
// if incarnation is active dude, it's sndStartId will be stored in sysData1, otherwise it will be data3
|
||||
if (pIncarnation->statnum == kStatDude && pIncarnation->type == kDudeModernCustom) pXSprite->sysData1 = pXIncarnation->sysData1;
|
||||
else pXSprite->sysData1 = pXIncarnation->data3;
|
||||
|
||||
pXSprite->data4 = pXIncarnation->data4;
|
||||
pXSprite->sysData1 = pXIncarnation->data3;
|
||||
pXSprite->sysData2 = pXIncarnation->data4;
|
||||
|
||||
pXSprite->dudeGuard = pXIncarnation->dudeGuard;
|
||||
pXSprite->dudeDeaf = pXIncarnation->dudeDeaf;
|
||||
|
@ -1762,8 +1758,7 @@ void genDudeTransform(spritetype* pSprite) {
|
|||
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);
|
||||
pXSprite->health = dudeGetStartHp(pSprite);
|
||||
|
||||
int seqId = dudeInfo[pSprite->type - kDudeBase].seqStartID;
|
||||
switch (pSprite->type) {
|
||||
|
@ -1793,8 +1788,10 @@ void genDudeTransform(spritetype* pSprite) {
|
|||
|
||||
break;
|
||||
}
|
||||
pXIncarnation->triggerOn = triggerOn;
|
||||
pXIncarnation->triggerOff = triggerOff;
|
||||
|
||||
// remove the incarnation in case if non-locked
|
||||
/*// remove the incarnation in case if non-locked
|
||||
if (pXIncarnation->locked == 0) {
|
||||
pXIncarnation->txID = pIncarnation->type = 0;
|
||||
actPostSprite(pIncarnation->index, kStatFree);
|
||||
|
@ -1802,7 +1799,7 @@ void genDudeTransform(spritetype* pSprite) {
|
|||
} else {
|
||||
pXIncarnation->triggerOn = triggerOn;
|
||||
pXIncarnation->triggerOff = triggerOff;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
|
@ -2159,5 +2156,40 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void genDudePostDeath(spritetype* pSprite, DAMAGE_TYPE damageType, int damage) {
|
||||
if (damageType == DAMAGE_TYPE_3) {
|
||||
DUDEINFO* pDudeInfo = getDudeInfo(pSprite->type);
|
||||
for (int i = 0; i < 3; i++)
|
||||
if (pDudeInfo->nGibType[i] > -1)
|
||||
GibSprite(pSprite, (GIBTYPE)pDudeInfo->nGibType[i], NULL, NULL);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
fxSpawnBlood(pSprite, damage);
|
||||
}
|
||||
|
||||
gKillMgr.AddKill(pSprite);
|
||||
|
||||
pSprite->type = kThingBloodChunks;
|
||||
actPostSprite(pSprite->index, kStatThing);
|
||||
}
|
||||
|
||||
void aiGenDudeInitSprite(spritetype* pSprite, XSPRITE* pXSprite) {
|
||||
switch (pSprite->type) {
|
||||
case kDudeModernCustom: {
|
||||
DUDEEXTRA_at6_u1* pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
|
||||
pDudeExtraE->at8 = pDudeExtraE->at0 = 0;
|
||||
aiGenDudeNewState(pSprite, &genDudeIdleL);
|
||||
break;
|
||||
}
|
||||
case kDudeModernCustomBurning:
|
||||
aiGenDudeNewState(pSprite, &genDudeBurnGoto);
|
||||
pXSprite->burnTime = 1200;
|
||||
break;
|
||||
}
|
||||
|
||||
pSprite->flags = 15;
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
END_BLD_NS
|
||||
|
|
|
@ -163,6 +163,7 @@ struct GENDUDEEXTRA {
|
|||
unsigned short weaponType;
|
||||
unsigned short baseDispersion;
|
||||
unsigned short slaveCount; // how many dudes is summoned
|
||||
//unsigned short incarnationsCount;
|
||||
signed short nLifeLeech; // spritenum of dropped dude's leech
|
||||
signed short slave[kGenDudeMaxSlaves]; // index of the ones dude is summon
|
||||
signed short dmgControl[kDamageMax]; // depends of current weapon, drop armor item, sprite yrepeat and surface type
|
||||
|
@ -218,8 +219,10 @@ int genDudeSeqStartId(XSPRITE* pXSprite);
|
|||
int getRangeAttackDist(spritetype* pSprite, int minDist = 1200, int maxDist = 80000);
|
||||
int getDispersionModifier(spritetype* pSprite, int minDisp, int maxDisp);
|
||||
void scaleDamage(XSPRITE* pXSprite);
|
||||
bool genDudePrepare(spritetype* pSprite, int propId = kGenDudePropertyAll);
|
||||
bool genDudePrepare(spritetype* pSprite, int propId);
|
||||
void genDudeUpdate(spritetype* pSprite);
|
||||
bool genDudeAdjustSlope(spritetype* pSprite, XSPRITE* pXSprite, int dist, int weaponType, int by = 64);
|
||||
void genDudePostDeath(spritetype* pSprite, DAMAGE_TYPE damageType, int damage);
|
||||
void aiGenDudeInitSprite(spritetype* pSprite, XSPRITE* pXSprite);
|
||||
#endif
|
||||
END_BLD_NS
|
||||
|
|
|
@ -46,6 +46,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include "triggers.h"
|
||||
#include "view.h"
|
||||
#include "nnexts.h"
|
||||
#include "aiunicult.h"
|
||||
|
||||
BEGIN_BLD_NS
|
||||
|
||||
|
@ -269,10 +270,17 @@ void Respawn(int nSprite) // 9
|
|||
pSprite->y = baseSprite[nSprite].y;
|
||||
pSprite->z = baseSprite[nSprite].z;
|
||||
pSprite->cstat |= 0x1101;
|
||||
pSprite->clipdist = getDudeInfo(nType+kDudeBase)->clipdist;
|
||||
pXSprite->health = getDudeInfo(nType+kDudeBase)->startHealth<<4;
|
||||
if (gSysRes.Lookup(getDudeInfo(nType+kDudeBase)->seqStartID, "SEQ"))
|
||||
seqSpawn(getDudeInfo(nType+kDudeBase)->seqStartID, 3, pSprite->extra, -1);
|
||||
pXSprite->health = dudeGetStartHp(pSprite);
|
||||
switch (pSprite->type) {
|
||||
default:
|
||||
pSprite->clipdist = getDudeInfo(nType + kDudeBase)->clipdist;
|
||||
if (gSysRes.Lookup(getDudeInfo(nType + kDudeBase)->seqStartID, "SEQ"))
|
||||
seqSpawn(getDudeInfo(nType + kDudeBase)->seqStartID, 3, pSprite->extra, -1);
|
||||
break;
|
||||
case kDudeModernCustom:
|
||||
seqSpawn(genDudeSeqStartId(pXSprite), 3, pSprite->extra, -1);
|
||||
break;
|
||||
}
|
||||
aiInitSprite(pSprite);
|
||||
pXSprite->key = 0;
|
||||
} else if (pSprite->type == kThingTNTBarrel) {
|
||||
|
@ -719,28 +727,6 @@ void callbackCondition(int nSprite) {
|
|||
|
||||
TRCONDITION* pCond = &gCondition[pXSprite->sysData1];
|
||||
for (int i = 0; i < pCond->length; i++) {
|
||||
/*if (pCond->obj[i].type == OBJ_SPRITE) {
|
||||
spritetype* pObj = &sprite[pCond->obj[i].index];
|
||||
XSPRITE* pXObj = (xspriRangeIsFine(pObj->extra)) ? &xsprite[pObj->extra] : NULL;
|
||||
if (gGameOptions.nGameType != 0) {
|
||||
if (pObj->type != pObj->inittype && pObj->inittype >= kDudePlayer1 && pObj->inittype <= kDudePlayer8) {
|
||||
PLAYER* pPlayer = getPlayerById(pObj->inittype);
|
||||
if (pPlayer) {
|
||||
pCond->obj[i].index = pPlayer->pSprite->index;
|
||||
viewSetSystemMessage("RESET INDEX");
|
||||
} else {
|
||||
viewSetSystemMessage("FAILED %d", pCond->obj[i].index);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
//if (pObj->flags & kHitagRespawn)
|
||||
//viewSetSystemMessage("TYPE: %d ON RESPAWN", pObj->type);
|
||||
//if (pObj->flags & kHitagFree) {
|
||||
// viewSetSystemMessage("TYPE: %d IS FREE", pObj->type);
|
||||
// }
|
||||
|
||||
}*/
|
||||
EVENT evn; evn.index = pCond->obj[i].index; evn.type = pCond->obj[i].type;
|
||||
evn.cmd = pCond->obj[i].cmd; evn.funcID = kCallbackCondition;
|
||||
useCondition(pXSprite, evn);
|
||||
|
|
|
@ -112,8 +112,9 @@ struct XSPRITE {
|
|||
unsigned int stateTimer : 16; // ai timer
|
||||
AISTATE* aiState; // ai
|
||||
#ifdef NOONE_EXTENSIONS
|
||||
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 sysData1: 32; // used to keep here various system data, so user can't change it in map editor
|
||||
signed int sysData2: 32; //
|
||||
unsigned int physAttr : 32; // currently used by additional physics sprites to keep it's attributes.
|
||||
#endif
|
||||
signed int scale; // used for scaling SEQ size on sprites
|
||||
|
||||
|
|
|
@ -1733,4 +1733,19 @@ DUDEINFO gPlayerTemplate[4] =
|
|||
|
||||
DUDEINFO fakeDudeInfo = {};
|
||||
|
||||
int dudeGetStartHp(spritetype* pDude) {
|
||||
|
||||
int hp = getDudeInfo(pDude->type)->startHealth << 4;
|
||||
if (!hp) {
|
||||
consoleSysMsg("Sprite #%d (type %d) is not a dude!", pDude->index, pDude->type);
|
||||
return hp;
|
||||
}
|
||||
#ifdef NOONE_EXTENSIONS
|
||||
// add a way to set custom hp for every enemy (data4 moved to sysData2)
|
||||
else if (gModernMap && xsprite[pDude->extra].sysData2 > 0)
|
||||
hp = ClipRange(xsprite[pDude->extra].sysData2 << 4, 1, 65535);
|
||||
#endif
|
||||
return hp;
|
||||
}
|
||||
|
||||
END_BLD_NS
|
||||
|
|
|
@ -66,4 +66,6 @@ inline DUDEINFO *getDudeInfo(int const nType)
|
|||
return &fakeDudeInfo;
|
||||
}
|
||||
|
||||
int dudeGetStartHp(spritetype* pDude);
|
||||
|
||||
END_BLD_NS
|
||||
|
|
|
@ -380,6 +380,33 @@ void nnExtInitModernStuff(bool bSaveLoad) {
|
|||
|
||||
} else {
|
||||
|
||||
/*// copy custom start health to avoid overwrite by kThingBloodChunks
|
||||
if (IsDudeSprite(pSprite))
|
||||
pXSprite->sysData2 = pXSprite->data4;
|
||||
|
||||
bool sysStat = false;
|
||||
switch (pSprite->statnum) {
|
||||
case kStatModernDudeTargetChanger:
|
||||
if (pSprite->type != kModernDudeTargetChanger) sysStat = true;
|
||||
break;
|
||||
case kStatModernCondition:
|
||||
if (pSprite->type != kModernCondition && pSprite->type != kModernConditionFalse) sysStat = true;
|
||||
break;
|
||||
case kStatModernEventRedirector:
|
||||
if (pSprite->type != kModernRandomTX && pSprite->type != kModernSequentialTX) sysStat = true;
|
||||
break;
|
||||
case kStatModernPlayerLinker:
|
||||
if (pSprite->type != kModernPlayerControl) sysStat = true;
|
||||
break;
|
||||
default:
|
||||
if (pSprite->statnum < kStatModernBase || pSprite->statnum >= kStatModernMax) break;
|
||||
ThrowError("Sprite status list number %d on sprite #%d is in a range of system reserved (%d - %d)!", pSprite->index, pSprite->statnum, kStatModernBase, kStatModernMax);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sysStat)
|
||||
ThrowError("Sprite #%d: System status list number %d detected!", pSprite->index, pSprite->statnum);
|
||||
*/
|
||||
switch (pSprite->type) {
|
||||
case kModernRandomTX:
|
||||
case kModernSequentialTX:
|
||||
|
@ -412,10 +439,43 @@ void nnExtInitModernStuff(bool bSaveLoad) {
|
|||
case kModernThingTNTProx:
|
||||
pXSprite->Proximity = true;
|
||||
break;
|
||||
case kDudeModernCustom:
|
||||
if (pXSprite->txID <= 0) break;
|
||||
for (int nSprite = headspritestat[kStatDude], found = 0; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
|
||||
XSPRITE* pXSpr = &xsprite[sprite[nSprite].extra];
|
||||
if (pXSpr->rxID != pXSprite->txID) continue;
|
||||
else if (found) ThrowError("\nCustom dude (TX ID %d):\nOnly one incarnation allowed per channel!", pXSprite->txID);
|
||||
changespritestat(nSprite, kStatInactive);
|
||||
nSprite = headspritestat[kStatDude];
|
||||
found++;
|
||||
}
|
||||
break;
|
||||
case kModernPlayerControl:
|
||||
if (pXSprite->command != kCmdLink) break;
|
||||
else if (pXSprite->data1 < 1 || pXSprite->data1 >= kMaxPlayers)
|
||||
ThrowError("\nPlayer Control (SPRITE #%d):\nPlayer out of a range (data1 = %d)", pSprite->index, pXSprite->data1);
|
||||
if (pXSprite->rxID && pXSprite->rxID != kChannelLevelStart)
|
||||
ThrowError("\nPlayer Control (SPRITE #%d) with Link command should have no RX ID!", pSprite->index, pXSprite->data1);
|
||||
|
||||
if (pXSprite->txID && pXSprite->txID < kChannelUser)
|
||||
ThrowError("\nPlayer Control (SPRITE #%d):\nTX ID should be in range of %d and %d!", pSprite->index, kChannelUser, kChannelMax);
|
||||
|
||||
// only one linker per player allowed
|
||||
for (int nSprite = headspritestat[kStatModernPlayerLinker]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
|
||||
XSPRITE* pXCtrl = &xsprite[sprite[nSprite].extra];
|
||||
if (pXSprite->data1 == pXCtrl->data1)
|
||||
ThrowError("\nPlayer Control (SPRITE #%d):\nPlayer %d already linked with different player control sprite #%d!", pSprite->index, pXSprite->data1, nSprite);
|
||||
}
|
||||
|
||||
pXSprite->rxID = kChannelLevelStart;
|
||||
pXSprite->triggerOnce = true;
|
||||
pXSprite->state = pXSprite->restState = pXSprite->waitTime = 0;
|
||||
changespritestat(pSprite->index, kStatModernPlayerLinker);
|
||||
break;
|
||||
case kModernCondition:
|
||||
if (pXSprite->waitTime > 0 && pXSprite->busyTime > 0) {
|
||||
pXSprite->busyTime += ((pXSprite->waitTime * 60) / 10); pXSprite->waitTime = 0;
|
||||
consoleSysMsg("Summing busyTime and waitTime for tracking condition #d%, RX ID %d. Result = %d ticks", pSprite->index, pXSprite->rxID, pXSprite->busyTime);
|
||||
consoleSysMsg("Summing busyTime and waitTime for tracking condition #%d, RX ID %d. Result = %d ticks", pSprite->index, pXSprite->rxID, pXSprite->busyTime);
|
||||
}
|
||||
|
||||
pXSprite->Decoupled = false; // must go through operateSprite always
|
||||
|
@ -430,7 +490,7 @@ void nnExtInitModernStuff(bool bSaveLoad) {
|
|||
break;
|
||||
}
|
||||
|
||||
// the following trigger flags are sensless to have together
|
||||
// the following trigger flags are senseless to have together
|
||||
if ((pXSprite->Touch && (pXSprite->Proximity || pXSprite->Sight) && pXSprite->DudeLockout)
|
||||
|| (pXSprite->Touch && pXSprite->Proximity && !pXSprite->Sight)) pXSprite->Touch = false;
|
||||
|
||||
|
@ -1194,8 +1254,11 @@ void trPlayerCtrlStopScene(XSPRITE* pXSource, PLAYER* pPlayer) {
|
|||
|
||||
}
|
||||
|
||||
void trPlayerCtrlLink(XSPRITE* pXSource, PLAYER* pPlayer) {
|
||||
void trPlayerCtrlLink(XSPRITE* pXSource, PLAYER* pPlayer, bool checkCondition) {
|
||||
|
||||
// save player's sprite index to use it later with conditions
|
||||
pXSource->sysData1 = pPlayer->nSprite;
|
||||
|
||||
pPlayer->pXSprite->txID = pXSource->txID;
|
||||
pPlayer->pXSprite->command = kCmdToggle;
|
||||
pPlayer->pXSprite->triggerOn = pXSource->triggerOn;
|
||||
|
@ -1224,17 +1287,19 @@ void trPlayerCtrlLink(XSPRITE* pXSource, PLAYER* pPlayer) {
|
|||
pPlayer->pXSprite->dropMsg = pXSource->dropMsg;
|
||||
|
||||
// let's check if there is tracking condition expecting objects with this TX id
|
||||
for (int i = bucketHead[pXSource->txID]; i < bucketHead[pXSource->txID + 1]; i++) {
|
||||
if (sprite[rxBucket[i].index].type == kModernCondition) {
|
||||
if (checkCondition && pXSource->txID >= kChannelUser) {
|
||||
for (int i = bucketHead[pXSource->txID]; i < bucketHead[pXSource->txID + 1]; i++) {
|
||||
if (sprite[rxBucket[i].index].type != kModernCondition) continue;
|
||||
|
||||
XSPRITE* pXCond = &xsprite[sprite[rxBucket[i].index].extra];
|
||||
if (pXCond->busyTime <= 0) continue;
|
||||
|
||||
// search for player control sprite and replace it with actual player sprite
|
||||
|
||||
TRCONDITION* pCond = &gCondition[pXCond->sysData1];
|
||||
// search for player control sprite and replace it with actual player sprite
|
||||
for (int k = 0; k < pCond->length; k++) {
|
||||
if (pCond->obj[k].index != pXSource->reference) continue;
|
||||
if (pCond->obj[k].type != OBJ_SPRITE || pCond->obj[k].index != pXSource->reference) continue;
|
||||
pCond->obj[k].index = pPlayer->nSprite;
|
||||
pCond->obj[k].cmd = kCmdToggle;
|
||||
pCond->obj[k].cmd = pPlayer->pXSprite->command;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2434,12 +2499,9 @@ bool condCheckDude(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS) {
|
|||
ThrowError("\nDude conditions:\nObject #%d (objType: %d) is not a dude!", objIndex, objType);
|
||||
|
||||
spritetype* pSpr = &sprite[objIndex];
|
||||
if (!xspriRangeIsFine(sprite[objIndex].extra)) {
|
||||
// TO-DO: must search for respawned player / enemy
|
||||
// there is currently serials for old sprite
|
||||
if (!xspriRangeIsFine(sprite[objIndex].extra))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
XSPRITE* pXSpr = &xsprite[pSpr->extra];
|
||||
if (pXSpr->health <= 0 || pSpr->type == kThingBloodChunks) return false;
|
||||
else if (cond < (kCondRange >> 1)) {
|
||||
|
@ -2604,11 +2666,11 @@ bool condCheckSprite(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS) {
|
|||
switch (cond) {
|
||||
default: break;
|
||||
case 50: // compare hp (in %)
|
||||
if (IsDudeSprite(pSpr)) var = ((pXSpr->data4 <= 0) ? getDudeInfo(pSpr->type)->startHealth : pXSpr->data4) << 4;
|
||||
if (IsDudeSprite(pSpr)) var = dudeGetStartHp(pSpr);
|
||||
else if (condCmpne(arg1, arg2, cmpOp) && pSpr->type == kThingBloodChunks) return true;
|
||||
else if (pSpr->type >= kThingBase && pSpr->type < kThingMax)
|
||||
var = thingInfo[pSpr->type - kThingBase].startHealth << 4;
|
||||
|
||||
|
||||
return condCmp((100 * pXSpr->health) / ClipLow(var, 1), arg1, arg2, cmpOp);
|
||||
case 55: // touching ceil of sector?
|
||||
if ((gSpriteHit[pSpr->extra].ceilhit & 0xc000) != 0x4000) return false;
|
||||
|
@ -2649,6 +2711,7 @@ bool condCheckSprite(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS) {
|
|||
return condCmp(getSpriteMassBySize(pSpr), arg1, arg2, cmpOp); // mass of the sprite in a range?
|
||||
}
|
||||
} else {
|
||||
viewSetSystemMessage("!!!!!!!! %d", pSpr->type);
|
||||
switch (cond) {
|
||||
default: return false;
|
||||
case 50:
|
||||
|
@ -2662,6 +2725,20 @@ bool condCheckSprite(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// this updates index of object in all tracking conditions
|
||||
void condUpdateObjectIndex(int objType, int oldIndex, int newIndex) {
|
||||
for (int i = 0; i <= gTrackingCondsCount; i++) {
|
||||
TRCONDITION* pCond = &gCondition[i];
|
||||
for (int k = 0; k < pCond->length; k++) {
|
||||
if (pCond->obj[k].type != objType || pCond->obj[k].index != oldIndex) continue;
|
||||
pCond->obj[k].index = newIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool valueIsBetween(int val, int min, int max) {
|
||||
return (val > min && val < max);
|
||||
}
|
||||
|
@ -3451,7 +3528,9 @@ bool modernTypeOperateSprite(int nSprite, spritetype* pSprite, XSPRITE* pXSprite
|
|||
/// !!! COMMANDS OF THE CURRENT SPRITE, NOT OF THE EVENT !!! ///
|
||||
switch (pXSprite->command) {
|
||||
case kCmdLink: // copy properties of sprite to player
|
||||
trPlayerCtrlLink(pXSprite, pPlayer);
|
||||
if (pXSprite->isTriggered) break;
|
||||
trPlayerCtrlLink(pXSprite, pPlayer, true);
|
||||
pXSprite->isTriggered = true;
|
||||
break;
|
||||
case kCmdNumberic: // player life form
|
||||
if (pXSprite->data2 < kModeHuman || pXSprite->data2 > kModeHumanShrink) break;
|
||||
|
@ -4119,10 +4198,9 @@ void useTargetChanger(XSPRITE* pXSource, spritetype* pSprite) {
|
|||
pXSprite->burnTime = 0;
|
||||
|
||||
// heal dude a bit in case of friendly fire
|
||||
if (pXSprite->data4 > 0 && pXSprite->health < pXSprite->data4)
|
||||
actHealDude(pXSprite, receiveHp, pXSprite->data4);
|
||||
else if (pXSprite->health < pDudeInfo->startHealth)
|
||||
actHealDude(pXSprite, receiveHp, pDudeInfo->startHealth);
|
||||
int startHp = dudeGetStartHp(pSprite);
|
||||
if (pXSprite->health < startHp) actHealDude(pXSprite, receiveHp, startHp);
|
||||
|
||||
} else if (xsprite[pBurnSource->extra].health <= 0) {
|
||||
pXSprite->burnTime = 0;
|
||||
}
|
||||
|
@ -4188,19 +4266,12 @@ void useTargetChanger(XSPRITE* pXSource, spritetype* pSprite) {
|
|||
spritetype* pMate = pTarget; XSPRITE* pXMate = pXTarget;
|
||||
|
||||
// heal dude
|
||||
if (pXSprite->data4 > 0 && pXSprite->health < pXSprite->data4)
|
||||
actHealDude(pXSprite, receiveHp, pXSprite->data4);
|
||||
else if (pXSprite->health < pDudeInfo->startHealth)
|
||||
actHealDude(pXSprite, receiveHp, pDudeInfo->startHealth);
|
||||
int startHp = dudeGetStartHp(pSprite);
|
||||
if (pXSprite->health < startHp) actHealDude(pXSprite, receiveHp, startHp);
|
||||
|
||||
// heal mate
|
||||
if (pXMate->data4 > 0 && pXMate->health < pXMate->data4)
|
||||
actHealDude(pXMate, receiveHp, pXMate->data4);
|
||||
else {
|
||||
DUDEINFO* pTDudeInfo = getDudeInfo(pMate->type);
|
||||
if (pXMate->health < pTDudeInfo->startHealth)
|
||||
actHealDude(pXMate, receiveHp, pTDudeInfo->startHealth);
|
||||
}
|
||||
startHp = dudeGetStartHp(pMate);
|
||||
if (pXMate->health < startHp) actHealDude(pXMate, receiveHp, startHp);
|
||||
|
||||
if (pXMate->target > -1 && sprite[pXMate->target].extra >= 0) {
|
||||
pTarget = &sprite[pXMate->target];
|
||||
|
|
|
@ -64,9 +64,12 @@ BEGIN_BLD_NS
|
|||
#define kCondRange 100
|
||||
// modern statnums
|
||||
enum {
|
||||
kStatModernBase = 20,
|
||||
kStatModernDudeTargetChanger = 20,
|
||||
kStatModernCondition = 21,
|
||||
kStatModernEventRedirector = 22,
|
||||
kStatModernPlayerLinker = 23,
|
||||
kStatModernMax = 64,
|
||||
};
|
||||
|
||||
// modern sprite types
|
||||
|
@ -277,7 +280,7 @@ void useRandomTx(XSPRITE* pXSource, COMMAND_ID cmd, bool setState);
|
|||
bool txIsRanged(XSPRITE* pXSource);
|
||||
void seqTxSendCmdAll(XSPRITE* pXSource, int nIndex, COMMAND_ID cmd, bool modernSend);
|
||||
// ------------------------------------------------------------------------- //
|
||||
void trPlayerCtrlLink(XSPRITE* pXSource, PLAYER* pPlayer);
|
||||
void trPlayerCtrlLink(XSPRITE* pXSource, PLAYER* pPlayer, bool checkCondition);
|
||||
void trPlayerCtrlSetRace(XSPRITE* pXSource, PLAYER* pPlayer);
|
||||
void trPlayerCtrlStartScene(XSPRITE* pXSource, PLAYER* pPlayer);
|
||||
void trPlayerCtrlStopScene(XSPRITE* pXSource, PLAYER* pPlayer);
|
||||
|
@ -331,11 +334,11 @@ bool condPush(XSPRITE* pXSprite, int objType, int objIndex);
|
|||
bool condRestore(XSPRITE* pXSprite);
|
||||
bool condCmp(int val, int arg1, int arg2, int comOp);
|
||||
bool condCmpne(int arg1, int arg2, int comOp);
|
||||
/*bool condCmpr(int val, int min, int max, int cmpOp);*/
|
||||
bool condCheckMixed(XSPRITE* pXCond, EVENT event, int cmpOp, bool PUSH, bool RVRS);
|
||||
bool condCheckSector(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS);
|
||||
bool condCheckWall(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS);
|
||||
bool condCheckSprite(XSPRITE* pXCond, int cmpOp, bool PUSH, bool RVRS);
|
||||
void condUpdateObjectIndex(int objType, int oldIndex, int newIndex);
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -650,7 +650,7 @@ void playerStart(int nPlayer, int bNewLevel)
|
|||
PLAYER* pPlayer = &gPlayer[nPlayer];
|
||||
GINPUT* pInput = &pPlayer->input;
|
||||
ZONE* pStartZone = NULL;
|
||||
|
||||
|
||||
// normal start position
|
||||
if (gGameOptions.nGameType <= 1)
|
||||
pStartZone = &gStartZone[nPlayer];
|
||||
|
@ -775,6 +775,20 @@ void playerStart(int nPlayer, int bNewLevel)
|
|||
pPlayer->weaponQav = -1;
|
||||
#ifdef NOONE_EXTENSIONS
|
||||
playerQavSceneReset(pPlayer); // reset qav scene
|
||||
|
||||
// we must check if properties of old pPlayer->pXSprite was
|
||||
// changed with kModernPlayerControl and copy it to the new x-sprite
|
||||
if (gModernMap && gGameOptions.nGameType != 0) {
|
||||
|
||||
for (int nSprite = headspritestat[kStatModernPlayerLinker]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
|
||||
XSPRITE* pXCtrl = &xsprite[sprite[nSprite].extra];
|
||||
if (pXCtrl->data1 != pPlayer->nPlayer + 1) continue;
|
||||
int nSpriteOld = pXCtrl->sysData1;
|
||||
trPlayerCtrlLink(pXCtrl, pPlayer, false);
|
||||
if (pPlayer->pXSprite->txID >= kChannelUser && gTrackingCondsCount > 0)
|
||||
condUpdateObjectIndex(OBJ_SPRITE, nSpriteOld, pXCtrl->sysData1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
pPlayer->hand = 0;
|
||||
pPlayer->nWaterPal = 0;
|
||||
|
|
Loading…
Reference in a new issue