mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-26 00:40:56 +00:00
- Rewrite true random, so it should work just fine now
- Way better AI for Custom Dude when attacking the target - Minor warning fixes and other updates # Conflicts: # source/blood/src/actor.cpp # source/blood/src/aiunicult.cpp # source/blood/src/aiunicult.h # source/blood/src/asound.cpp # source/blood/src/gameutil.cpp # source/blood/src/gameutil.h # source/blood/src/player.h # source/blood/src/triggers.h
This commit is contained in:
parent
a6bf1c3026
commit
da47ebbd2c
20 changed files with 757 additions and 442 deletions
|
@ -1516,7 +1516,9 @@ MissileType missileInfo[] = {
|
|||
40,
|
||||
(char)-16,
|
||||
16,
|
||||
1207, 1207
|
||||
1207, 1207,
|
||||
false, false, false, false, false, true, false
|
||||
|
||||
},
|
||||
// Regular flare
|
||||
{
|
||||
|
@ -1527,7 +1529,8 @@ MissileType missileInfo[] = {
|
|||
32,
|
||||
(char)-128,
|
||||
32,
|
||||
420, 420
|
||||
420, 420,
|
||||
false, true, true, false, false, false, false
|
||||
},
|
||||
// Tesla alt
|
||||
{
|
||||
|
@ -1538,7 +1541,8 @@ MissileType missileInfo[] = {
|
|||
32,
|
||||
(char)-128,
|
||||
32,
|
||||
471, 471
|
||||
471, 471,
|
||||
false, false, false, false, false, false, true
|
||||
},
|
||||
// Flare alt
|
||||
{
|
||||
|
@ -1549,7 +1553,8 @@ MissileType missileInfo[] = {
|
|||
32,
|
||||
(char)-128,
|
||||
4,
|
||||
421, 421
|
||||
421, 421,
|
||||
false, true, false, true, false, false, false
|
||||
},
|
||||
// Spray flame
|
||||
{
|
||||
|
@ -1560,7 +1565,8 @@ MissileType missileInfo[] = {
|
|||
24,
|
||||
(char)-128,
|
||||
16,
|
||||
1309, 351
|
||||
1309, 351,
|
||||
false, true, false, false, false, false, false
|
||||
},
|
||||
// Fireball
|
||||
{
|
||||
|
@ -1571,7 +1577,8 @@ MissileType missileInfo[] = {
|
|||
32,
|
||||
(char)-128,
|
||||
32,
|
||||
480, 480
|
||||
480, 480,
|
||||
false, true, false, true, false, false, false
|
||||
},
|
||||
// Tesla regular
|
||||
{
|
||||
|
@ -1582,7 +1589,8 @@ MissileType missileInfo[] = {
|
|||
32,
|
||||
(char)-128,
|
||||
16,
|
||||
470, 470
|
||||
470, 470,
|
||||
false, false, false, false, false, false, true
|
||||
},
|
||||
// EctoSkull
|
||||
{
|
||||
|
@ -1593,7 +1601,8 @@ MissileType missileInfo[] = {
|
|||
32,
|
||||
(char)-24,
|
||||
32,
|
||||
489, 490
|
||||
489, 490,
|
||||
false, false, false, false, false, true, false
|
||||
},
|
||||
// Hellhound flame
|
||||
{
|
||||
|
@ -1604,7 +1613,8 @@ MissileType missileInfo[] = {
|
|||
24,
|
||||
(char)-128,
|
||||
16,
|
||||
462, 351
|
||||
462, 351,
|
||||
false, true, false, false, false, false, false
|
||||
},
|
||||
// Puke
|
||||
{
|
||||
|
@ -1615,7 +1625,8 @@ MissileType missileInfo[] = {
|
|||
16,
|
||||
(char)-16,
|
||||
16,
|
||||
1203, 172
|
||||
1203, 172,
|
||||
false, false, true, false, false, false, false
|
||||
},
|
||||
// Reserved
|
||||
{
|
||||
|
@ -1626,7 +1637,8 @@ MissileType missileInfo[] = {
|
|||
8,
|
||||
(char)0,
|
||||
16,
|
||||
0,0
|
||||
0,0,
|
||||
false, false, true, false, false, false, false
|
||||
},
|
||||
// Stone gargoyle projectile
|
||||
{
|
||||
|
@ -1637,7 +1649,8 @@ MissileType missileInfo[] = {
|
|||
32,
|
||||
(char)-128,
|
||||
16,
|
||||
1457, 249
|
||||
1457, 249,
|
||||
false, false, false, false, false, true, false
|
||||
},
|
||||
// Napalm launcher
|
||||
{
|
||||
|
@ -1648,7 +1661,8 @@ MissileType missileInfo[] = {
|
|||
30,
|
||||
(char)-128,
|
||||
24,
|
||||
480, 489
|
||||
480, 489,
|
||||
false, true, false, true, false, false, false
|
||||
},
|
||||
// Cerberus fireball
|
||||
{
|
||||
|
@ -1659,7 +1673,8 @@ MissileType missileInfo[] = {
|
|||
30,
|
||||
(char)-128,
|
||||
24,
|
||||
480, 489
|
||||
480, 489,
|
||||
false, false, false, true, false, false, false
|
||||
},
|
||||
// Tchernobog fireball
|
||||
{
|
||||
|
@ -1670,7 +1685,8 @@ MissileType missileInfo[] = {
|
|||
24,
|
||||
(char)-128,
|
||||
16,
|
||||
480, 489
|
||||
480, 489,
|
||||
false, false, false, true, false, false, false
|
||||
},
|
||||
// Regular life leech
|
||||
{
|
||||
|
@ -1681,7 +1697,8 @@ MissileType missileInfo[] = {
|
|||
32,
|
||||
(char)-128,
|
||||
16,
|
||||
491, 491
|
||||
491, 491,
|
||||
true, true, true, true, true, true, true
|
||||
},
|
||||
// Dropped life leech (enough ammo)
|
||||
{
|
||||
|
@ -1692,7 +1709,8 @@ MissileType missileInfo[] = {
|
|||
16,
|
||||
(char)-128,
|
||||
16,
|
||||
520, 520
|
||||
520, 520,
|
||||
false, false, false, false, false, true, false
|
||||
},
|
||||
// Dropped life leech (no ammo)
|
||||
{
|
||||
|
@ -1703,7 +1721,8 @@ MissileType missileInfo[] = {
|
|||
32,
|
||||
(char)-128,
|
||||
16,
|
||||
520, 520
|
||||
520, 520,
|
||||
false, false, false, false, false, true, false
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2446,7 +2465,7 @@ struct POSTPONE {
|
|||
|
||||
POSTPONE gPost[kMaxSprites];
|
||||
|
||||
static char buffer[120];
|
||||
//static char buffer[120];
|
||||
|
||||
bool IsItemSprite(spritetype *pSprite)
|
||||
{
|
||||
|
@ -3102,7 +3121,6 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
|
|||
if (!IsDudeSprite(pSprite) || gGenDudeExtra[pSprite->owner].slave[i] == pSprite->index || pXSprite->health <= 0) {
|
||||
gGenDudeExtra[pSprite->owner].slave[i] = -1;
|
||||
gGenDudeExtra[pSprite->owner].slaveCount = ClipRange(gGenDudeExtra[pSprite->owner].slaveCount - 1, 0, gGameOptions.nDifficulty + 1);
|
||||
//viewSetSystemMessage("REMOVING %d FROM %d, COUNT: %d", pSprite->index, sprite[pSprite->owner].type, gGenDudeExtra[pSprite->owner].slaveCount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3113,19 +3131,19 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
|
|||
|
||||
switch (pSprite->type) {
|
||||
case kDudeModernCustom: {
|
||||
|
||||
GENDUDEEXTRA* pExtra = genDudeExtra(pSprite);
|
||||
removeDudeStuff(pSprite);
|
||||
if (pXSprite->txID <= 0 || getNextIncarnation(pXSprite) == NULL) {
|
||||
|
||||
if (pXSprite->data1 >= kTrapExploder && pXSprite->data1 < (kTrapExploder + kExplodeMax) - 1 &&
|
||||
Chance(0x4000) && damageType != 5 && damageType != 4) {
|
||||
|
||||
if (pExtra->weaponType == kGenDudeWeaponKamikaze && Chance(0x4000) && damageType != 5 && damageType != 4) {
|
||||
doExplosion(pSprite, pXSprite->data1 - kTrapExploder);
|
||||
if (Chance(0x9000)) damageType = (DAMAGE_TYPE) 3;
|
||||
}
|
||||
|
||||
if (damageType == DAMAGE_TYPE_1) {
|
||||
if ((gSysRes.Lookup(pXSprite->data2 + 15, "SEQ") || gSysRes.Lookup(pXSprite->data2 + 16, "SEQ")) && pXSprite->medium == kMediumNormal) {
|
||||
if (gSysRes.Lookup(pXSprite->data2 + 3, "SEQ")) {
|
||||
if (pExtra->availDeaths[DAMAGE_TYPE_1] && !spriteIsUnderwater(pSprite)) {
|
||||
if (pExtra->canBurn) {
|
||||
pSprite->type = kDudeModernCustomBurning;
|
||||
if (pXSprite->data2 == kGenDudeDefaultSeq) // don't inherit palette for burning if using default animation
|
||||
pSprite->pal = 0;
|
||||
|
@ -3158,11 +3176,12 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
|
|||
|
||||
|
||||
pSprite->flags &= ~kPhysMove; xvel[pSprite->index] = yvel[pSprite->index] = 0;
|
||||
|
||||
int seqId = pXSprite->data2 + 18;
|
||||
if (!gSysRes.Lookup(seqId, "SEQ")) {
|
||||
|
||||
playGenDudeSound(pSprite, kGenDudeSndTransforming);
|
||||
int seqId = pXSprite->data2 + kGenDudeSeqTransform;
|
||||
if (gSysRes.Lookup(seqId, "SEQ")) seqSpawn(seqId, 3, nXSprite, -1);
|
||||
else {
|
||||
seqKill(3, nXSprite);
|
||||
playGenDudeSound(pSprite, kGenDudeSndTransforming);
|
||||
spritetype* pEffect = gFX.fxSpawn((FX_ID)52, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, pSprite->ang);
|
||||
if (pEffect != NULL) {
|
||||
pEffect->cstat = CSTAT_SPRITE_ALIGNMENT_FACING;
|
||||
|
@ -3170,7 +3189,7 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
|
|||
pEffect->xrepeat = pSprite->xrepeat;
|
||||
pEffect->yrepeat = pSprite->yrepeat;
|
||||
}
|
||||
|
||||
|
||||
GIBTYPE nGibType;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (Chance(0x3000)) nGibType = GIBTYPE_6;
|
||||
|
@ -3183,14 +3202,9 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
|
|||
CGibVelocity gibVel(xvel[pSprite->index] >> 1, yvel[pSprite->index] >> 1, -0xccccc);
|
||||
GibSprite(pSprite, nGibType, &gibPos, &gibVel);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
seqSpawn(seqId, 3, nXSprite, -1);
|
||||
playGenDudeSound(pSprite, kGenDudeSndTransforming);
|
||||
|
||||
|
||||
pXSprite->sysData1 = kGenDudeTransformStatus; // in transform
|
||||
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
@ -3289,9 +3303,14 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType,
|
|||
nSeq = 2;
|
||||
switch (pSprite->type) {
|
||||
case kDudeModernCustom:
|
||||
case kDudeModernCustomBurning:
|
||||
case kDudeModernCustomBurning: {
|
||||
playGenDudeSound(pSprite, kGenDudeSndDeathExplode);
|
||||
GENDUDEEXTRA* pExtra = genDudeExtra(pSprite);
|
||||
if (!pExtra->availDeaths[damageType]) {
|
||||
nSeq = 1; damageType = DAMAGE_TYPE_0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kDudeCultistTommy:
|
||||
case kDudeCultistShotgun:
|
||||
case kDudeCultistTommyProne:
|
||||
|
@ -4321,7 +4340,7 @@ void ProcessTouchObjects(spritetype *pSprite, int nXSprite)
|
|||
}
|
||||
}
|
||||
|
||||
switch (pSprite->type) {
|
||||
/*switch (pSprite->type) {
|
||||
case kDudeModernCustom:
|
||||
case kDudeModernCustomBurning:
|
||||
{
|
||||
|
@ -4338,7 +4357,7 @@ void ProcessTouchObjects(spritetype *pSprite, int nXSprite)
|
|||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
switch (pSprite2->type) {
|
||||
case kThingKickablePail:
|
||||
|
@ -4395,7 +4414,7 @@ void ProcessTouchObjects(spritetype *pSprite, int nXSprite)
|
|||
}
|
||||
}
|
||||
|
||||
switch (pSprite->type) {
|
||||
/*switch (pSprite->type) {
|
||||
case kDudeModernCustom:
|
||||
case kDudeModernCustomBurning:
|
||||
{
|
||||
|
@ -4411,7 +4430,7 @@ void ProcessTouchObjects(spritetype *pSprite, int nXSprite)
|
|||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
switch (pSprite2->type) {
|
||||
|
@ -4848,7 +4867,7 @@ void MoveDude(spritetype *pSprite)
|
|||
ChangeSpriteSect(nSprite, nSector);
|
||||
|
||||
nXSector = sector[nSector].extra;
|
||||
pXSector = (nXSector > 0) ? pXSector = &xsector[nXSector] : NULL;
|
||||
pXSector = (nXSector > 0) ? &xsector[nXSector] : NULL;
|
||||
if (pXSector && pXSector->Enter && (pPlayer || !pXSector->dudeLockout)) {
|
||||
|
||||
if (sector[nSector].type == kSectorTeleport)
|
||||
|
@ -5425,7 +5444,7 @@ void actExplodeSprite(spritetype *pSprite)
|
|||
return;
|
||||
sfxKill3DSound(pSprite, -1, -1);
|
||||
evKill(pSprite->index, 3);
|
||||
int nType;
|
||||
int nType = 1;
|
||||
switch (pSprite->type)
|
||||
{
|
||||
case kMissileFireballNapam:
|
||||
|
@ -6151,10 +6170,11 @@ void actProcessSprites(void)
|
|||
}
|
||||
|
||||
// By NoOne: handle incarnations of custom dude
|
||||
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);
|
||||
if (pSprite->type == kDudeModernCustom && pXSprite->txID > 0 && pXSprite->sysData1 == kGenDudeTransformStatus) {
|
||||
xvel[pSprite->index] = yvel[pSprite->index] = 0;
|
||||
if (seqGetStatus(3, nXSprite) < 0) {
|
||||
XSPRITE* pXIncarnation = getNextIncarnation(pXSprite);
|
||||
if (seqGetStatus(3, nXSprite) < 0 && pXIncarnation != NULL) {
|
||||
if (pXIncarnation != NULL) {
|
||||
spritetype* pIncarnation = &sprite[pXIncarnation->reference];
|
||||
pXSprite->key = pXSprite->dropMsg = pXSprite->locked = 0;
|
||||
|
||||
|
@ -6189,11 +6209,11 @@ void actProcessSprites(void)
|
|||
|
||||
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 pXIncarnation->data3;
|
||||
|
||||
else pXSprite->sysData1 = pXIncarnation->data3;
|
||||
|
||||
pXSprite->data4 = pXIncarnation->data4;
|
||||
|
||||
pXSprite->dudeGuard = pXIncarnation->dudeGuard;
|
||||
|
@ -6203,7 +6223,7 @@ void actProcessSprites(void)
|
|||
|
||||
pXSprite->dropMsg = pXIncarnation->dropMsg;
|
||||
pXSprite->key = pXIncarnation->key;
|
||||
|
||||
|
||||
pXSprite->locked = pXIncarnation->locked;
|
||||
pXSprite->Decoupled = pXIncarnation->Decoupled;
|
||||
|
||||
|
@ -6212,8 +6232,8 @@ void actProcessSprites(void)
|
|||
|
||||
// set hp
|
||||
if (pXSprite->data4 <= 0) pXSprite->health = dudeInfo[pSprite->type - kDudeBase].startHealth << 4;
|
||||
else pXSprite->health = ClipRange(pXSprite->data4 << 4, 1, 65535);
|
||||
|
||||
else pXSprite->health = ClipRange(pXSprite->data4 << 4, 1, 65535);
|
||||
|
||||
int seqId = dudeInfo[pSprite->type - kDudeBase].seqStartID;
|
||||
switch (pSprite->type) {
|
||||
case kDudePodMother: // fake dude
|
||||
|
@ -6226,7 +6246,7 @@ void actProcessSprites(void)
|
|||
fallthrough__; // go below
|
||||
default:
|
||||
seqSpawn(seqId, 3, nXSprite, -1);
|
||||
|
||||
|
||||
// save target
|
||||
int target = pXSprite->target;
|
||||
|
||||
|
@ -6239,13 +6259,12 @@ void actProcessSprites(void)
|
|||
|
||||
// finally activate it
|
||||
aiActivateDude(pSprite, pXSprite);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// remove the incarnation in case if non-locked
|
||||
if (pXIncarnation->locked == 0) {
|
||||
|
||||
pXIncarnation->txID = pIncarnation->type = 0;
|
||||
actPostSprite(pIncarnation->xvel, kStatFree);
|
||||
// or restore triggerOn and off options
|
||||
|
@ -6253,14 +6272,13 @@ void actProcessSprites(void)
|
|||
pXIncarnation->triggerOn = triggerOn;
|
||||
pXIncarnation->triggerOff = triggerOff;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (pXSprite->sysData1 == kGenDudeTransformStatus) pXSprite->sysData1 = 0;
|
||||
// just trigger dude death
|
||||
trTriggerSprite(nSprite, pXSprite, kCmdOff, pSprite->owner);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pSprite->type == kDudeCerberusTwoHead)
|
||||
{
|
||||
|
@ -7339,89 +7357,58 @@ int GetDataVal(spritetype* pSprite, int data) {
|
|||
}
|
||||
|
||||
|
||||
std::default_random_engine rng;
|
||||
int my_random(int a, int b) {
|
||||
|
||||
int STD_Random(int a, int b) {
|
||||
|
||||
|
||||
std::default_random_engine rng;
|
||||
rng.seed(std::random_device()());
|
||||
std::uniform_int_distribution<int> dist_a_b(a, b);
|
||||
return dist_a_b(rng);
|
||||
}
|
||||
|
||||
// tries to get random data field of sprite
|
||||
int GetRandDataVal(int *rData, spritetype* pSprite) {
|
||||
int temp[4];
|
||||
if (rData != NULL && pSprite != NULL) return -1;
|
||||
else if (pSprite != NULL) {
|
||||
|
||||
if (pSprite->extra < 0)
|
||||
return -1;
|
||||
|
||||
if (rData == NULL)
|
||||
rData = temp;
|
||||
|
||||
XSPRITE* pXSprite = &xsprite[pSprite->extra];
|
||||
rData[0] = pXSprite->data1; rData[2] = pXSprite->data3;
|
||||
rData[1] = pXSprite->data2; rData[3] = pXSprite->data4;
|
||||
|
||||
}
|
||||
else if (rData == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int random = 0;
|
||||
int GetRandDataVal(int *rData) {
|
||||
dassert(rData != NULL);
|
||||
int random = 0, a = 0; int first = -1; int maxRetries = 10;
|
||||
|
||||
// randomize only in case if at least 2 data fields are not empty
|
||||
int a = 1; int b = -1;
|
||||
for (int i = 0; i <= 3; i++) {
|
||||
if (rData[i] == 0) {
|
||||
if (a++ > 2)
|
||||
return -1;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (rData[i] <= 0 && a++ > 1) return -1;
|
||||
else if (first == -1) first = rData[i];
|
||||
}
|
||||
else if (b == -1) {
|
||||
b++;
|
||||
}
|
||||
}
|
||||
|
||||
// try randomize few times
|
||||
int maxRetries = 10;
|
||||
while (maxRetries > 0) {
|
||||
|
||||
// use true random only for single player mode
|
||||
// otherwise use Blood's default one. In the future it maybe possible to make
|
||||
// host send info to clients about what was generated.
|
||||
|
||||
if (gGameOptions.nGameType != 0 || VanillaMode() || DemoRecordStatus()) random = Random(3);
|
||||
else {
|
||||
rng.seed(std::random_device()());
|
||||
random = my_random(0, 4);
|
||||
}
|
||||
|
||||
// use true random only for single player mode, otherwise use Blood's default one.
|
||||
random = (gGameOptions.nGameType == 0 && !VanillaMode() && !DemoRecordStatus()) ? STD_Random(0, 3) : Random(3);
|
||||
if (rData[random] > 0) return rData[random];
|
||||
maxRetries--;
|
||||
else maxRetries--;
|
||||
}
|
||||
|
||||
// if nothing, get first found data value from top
|
||||
return rData[b];
|
||||
return first;
|
||||
}
|
||||
|
||||
// this function drops random item using random pickup generator(s)
|
||||
spritetype* DropRandomPickupObject(spritetype* pSprite, short prevItem) {
|
||||
spritetype* pSprite2 = NULL;
|
||||
|
||||
int rData[4]; int selected = -1;
|
||||
rData[0] = xsprite[pSprite->extra].data1; rData[2] = xsprite[pSprite->extra].data3;
|
||||
rData[1] = xsprite[pSprite->extra].data2; rData[3] = xsprite[pSprite->extra].data4;
|
||||
spritetype* pSprite2 = NULL; int* rData = xspriData2Array(pSprite->extra);
|
||||
int selected = -1;
|
||||
|
||||
if (rData != NULL) {
|
||||
|
||||
// randomize only in case if at least 2 data fields fits.
|
||||
for (int i = 0; i <= 3; i++)
|
||||
if (rData[i] < kItemWeaponBase || rData[i] >= kItemMax)
|
||||
rData[i] = 0;
|
||||
|
||||
int maxRetries = 9;
|
||||
while ((selected = GetRandDataVal(rData, NULL)) == prevItem) if (maxRetries-- <= 0) break;
|
||||
while ((selected = GetRandDataVal(rData)) == prevItem) if (maxRetries-- <= 0) break;
|
||||
if (selected > 0) {
|
||||
spritetype* pSource = pSprite; XSPRITE* pXSource = &xsprite[pSource->extra];
|
||||
pSprite2 = actDropObject(pSprite, selected);
|
||||
if (pSprite2 != NULL) {
|
||||
|
||||
|
||||
pXSource->dropMsg = pSprite2->type; // store dropped item type in dropMsg
|
||||
pSprite2->x = pSource->x;
|
||||
pSprite2->y = pSource->y;
|
||||
|
@ -7429,8 +7416,8 @@ spritetype* DropRandomPickupObject(spritetype* pSprite, short prevItem) {
|
|||
|
||||
if ((pSource->flags & kModernTypeFlag1) && (pXSource->txID > 0 || (pXSource->txID != 3 && pXSource->lockMsg > 0)) &&
|
||||
dbInsertXSprite(pSprite2->xvel) > 0) {
|
||||
|
||||
XSPRITE * pXSprite2 = &xsprite[pSprite2->extra];
|
||||
|
||||
XSPRITE* pXSprite2 = &xsprite[pSprite2->extra];
|
||||
|
||||
// inherit spawn sprite trigger settings, so designer can send command when item picked up.
|
||||
pXSprite2->txID = pXSource->txID;
|
||||
|
@ -7444,27 +7431,24 @@ spritetype* DropRandomPickupObject(spritetype* pSprite, short prevItem) {
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return pSprite2;
|
||||
}
|
||||
|
||||
// this function spawns random dude using dudeSpawn
|
||||
spritetype* spawnRandomDude(spritetype* pSprite) {
|
||||
spritetype* pSprite2 = NULL;
|
||||
|
||||
if (pSprite->extra >= 0) {
|
||||
int rData[4]; int selected = -1;
|
||||
rData[0] = xsprite[pSprite->extra].data1; rData[2] = xsprite[pSprite->extra].data3;
|
||||
rData[1] = xsprite[pSprite->extra].data2; rData[3] = xsprite[pSprite->extra].data4;
|
||||
|
||||
int* rData = xspriData2Array(pSprite->extra); int selected = -1;
|
||||
if (rData != NULL) {
|
||||
// randomize only in case if at least 2 data fields fits.
|
||||
for (int i = 0; i <= 3; i++)
|
||||
if (rData[i] < kDudeBase || rData[i] >= kDudeMax)
|
||||
rData[i] = 0;
|
||||
|
||||
if ((selected = GetRandDataVal(rData,NULL)) > 0)
|
||||
|
||||
if ((selected = GetRandDataVal(rData)) > 0)
|
||||
pSprite2 = actSpawnDude(pSprite, selected, -1, 0);
|
||||
}
|
||||
|
||||
return pSprite2;
|
||||
}
|
||||
//-------------------------
|
||||
|
@ -7529,7 +7513,7 @@ spritetype* actSpawnCustomDude(spritetype* pSprite, int nDist) {
|
|||
if (pSource->clipdist > 0) pDude->clipdist = pSource->clipdist;
|
||||
|
||||
// inherit custom hp settings
|
||||
if (pXSource->data4 <= 0) pXDude->health = dudeInfo[nType].startHealth << 4;
|
||||
if (pXSource->data4 <= 0) pXDude->health = dudeInfo[nType - kDudeBase].startHealth << 4;
|
||||
else pXDude->health = ClipRange(pXSource->data4 << 4, 1, 65535);
|
||||
|
||||
|
||||
|
@ -7666,7 +7650,6 @@ int getSpriteMassBySize(spritetype* pSprite) {
|
|||
cached->picnum = pSprite->picnum; cached->seqId = seqId;
|
||||
cached->clipdist = pSprite->clipdist;
|
||||
|
||||
//viewSetSystemMessage("MASS: %d", cached->mass);
|
||||
return cached->mass;
|
||||
}
|
||||
|
||||
|
@ -7738,9 +7721,9 @@ void debrisMove(int listIndex) {
|
|||
int top, bottom; GetSpriteExtents(pSprite, &top, &bottom);
|
||||
|
||||
int moveHit = 0;
|
||||
int floorDist = (bottom - pSprite->z) / 4;
|
||||
int ceilDist = (pSprite->z - top) / 4;
|
||||
int clipDist = pSprite->clipdist << 2;
|
||||
//int floorDist = (bottom - pSprite->z) / 4;
|
||||
//int ceilDist = (pSprite->z - top) / 4;
|
||||
//int clipDist = pSprite->clipdist << 2;
|
||||
|
||||
int tmpFraction = gSpriteMass[pSprite->extra].fraction;
|
||||
if (sector[nSector].extra >= 0 && xsector[sector[nSector].extra].Underwater)
|
||||
|
@ -7826,7 +7809,7 @@ void debrisMove(int listIndex) {
|
|||
if (v20 > 0) {
|
||||
|
||||
pXDebris->physAttr |= kPhysFalling;
|
||||
int vax = actFloorBounceVector((int*)& xvel[nSprite], (int*)& yvel[nSprite], (int*)& v20, pSprite->sectnum, tmpFraction);
|
||||
actFloorBounceVector((int*)& xvel[nSprite], (int*)& yvel[nSprite], (int*)& v20, pSprite->sectnum, tmpFraction);
|
||||
zvel[nSprite] = v20;
|
||||
|
||||
if (velFloor[pSprite->sectnum] == 0 && klabs(zvel[nSprite]) < 0x10000) {
|
||||
|
@ -7918,4 +7901,18 @@ bool ceilIsTooLow(spritetype* pSprite) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool isImmune(spritetype* pSprite, int dmgType, int minScale) {
|
||||
|
||||
if (dmgType >= kDmgFall && dmgType < kDmgMax && pSprite->extra >= 0 && xsprite[pSprite->extra].locked != 1) {
|
||||
if (pSprite->type >= kThingBase && pSprite->type < kThingMax)
|
||||
return (thingInfo[pSprite->type - kThingBase].dmgControl[dmgType] <= minScale);
|
||||
else if (IsDudeSprite(pSprite)) {
|
||||
if (IsPlayerSprite(pSprite)) return (gPlayer[pSprite->type - kDudePlayer1].damageControl[dmgType] <= minScale);
|
||||
else if (pSprite->type == kDudeModernCustom) return (gGenDudeExtra[pSprite->index].dmgControl[dmgType] <= minScale);
|
||||
else return (dudeInfo[pSprite->type - kDudeBase].at70[dmgType] <= minScale);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
END_BLD_NS
|
||||
|
|
|
@ -133,6 +133,7 @@ struct MissileType
|
|||
char shade;
|
||||
unsigned char clipDist;
|
||||
int fireSound[2]; // By NoOne: predefined fire sounds. used by kDudeModernCustom, but can be used for something else.
|
||||
bool dmgType[kDamageMax]; // By NoOne: list of damages types missile can use
|
||||
};
|
||||
|
||||
struct EXPLOSION
|
||||
|
@ -268,8 +269,8 @@ void MakeSplash(spritetype *pSprite, XSPRITE *pXSprite);
|
|||
spritetype* DropRandomPickupObject(spritetype* pSprite, short prevItem);
|
||||
spritetype* spawnRandomDude(spritetype* pSprite);
|
||||
int GetDataVal(spritetype* pSprite, int data);
|
||||
int my_random(int a, int b);
|
||||
int GetRandDataVal(int *rData, spritetype* pSprite);
|
||||
int STD_Random(int a, int b);
|
||||
int GetRandDataVal(int *rData);
|
||||
bool sfxPlayMissileSound(spritetype* pSprite, int missileId);
|
||||
bool sfxPlayVectorSound(spritetype* pSprite, int vectorId);
|
||||
spritetype* actSpawnCustomDude(spritetype* pSprite, int nDist);
|
||||
|
@ -280,6 +281,7 @@ int isDebris(int nSprite);
|
|||
int debrisGetFreeIndex(void);
|
||||
void debrisMove(int listIndex);
|
||||
void debrisConcuss(int nOwner, int listIndex, int x, int y, int z, int dmg);
|
||||
bool isImmune(spritetype* pSprite, int dmgType, int minScale = 16);
|
||||
|
||||
extern SPRITEMASS gSpriteMass[kMaxXSprites];
|
||||
extern short gProxySpritesList[kMaxSuperXSprites];
|
||||
|
|
|
@ -124,12 +124,6 @@ void aiNewState(spritetype *pSprite, XSPRITE *pXSprite, AISTATE *pAIState)
|
|||
pAIState->enterFunc(pSprite, pXSprite);
|
||||
}
|
||||
|
||||
bool dudeIsImmune(spritetype* pSprite, int dmgType) {
|
||||
if (dmgType < 0 || dmgType > 6) return true;
|
||||
else if (dudeInfo[pSprite->type - kDudeBase].startDamage[dmgType] == 0) return true;
|
||||
else if (pSprite->extra >= 0 && xsprite[pSprite->extra].locked == 1) return true; // if dude is locked, it immune to any dmg.
|
||||
return false;
|
||||
}
|
||||
bool CanMove(spritetype *pSprite, int a2, int nAngle, int nRange)
|
||||
{
|
||||
int top, bottom;
|
||||
|
@ -171,7 +165,7 @@ bool CanMove(spritetype *pSprite, int a2, int nAngle, int nRange)
|
|||
switch (pSprite->type) {
|
||||
case kDudeCerberusTwoHead: // Cerberus
|
||||
case kDudeCerberusOneHead: // 1 Head Cerberus
|
||||
if (VanillaMode() || !dudeIsImmune(pSprite, pXSector->damageType))
|
||||
if (VanillaMode() || !isImmune(pSprite, pXSector->damageType))
|
||||
Crusher = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -233,7 +227,7 @@ bool CanMove(spritetype *pSprite, int a2, int nAngle, int nRange)
|
|||
break;
|
||||
case kDudeModernCustom:
|
||||
case kDudeModernCustomBurning:
|
||||
if ((Crusher && !dudeIsImmune(pSprite, pXSector->damageType)) || ((Water || Underwater) && !canSwim(pSprite))) return false;
|
||||
if ((Crusher && !isImmune(pSprite, pXSector->damageType)) || ((Water || Underwater) && !canSwim(pSprite))) return false;
|
||||
return true;
|
||||
fallthrough__;
|
||||
case kDudeZombieAxeNormal:
|
||||
|
@ -1025,7 +1019,7 @@ int aiDamageSprite(spritetype *pSprite, XSPRITE *pXSprite, int nSource, DAMAGE_T
|
|||
else if (pXSprite->txID <= 0 || getNextIncarnation(pXSprite) == NULL) {
|
||||
removeDudeStuff(pSprite);
|
||||
|
||||
if (pExtra->curWeapon >= kTrapExploder && pExtra->curWeapon < (kTrapExploder + kExplodeMax) - 1)
|
||||
if (pExtra->weaponType == kGenDudeWeaponKamikaze)
|
||||
doExplosion(pSprite, pXSprite->data1 - kTrapExploder);
|
||||
|
||||
if (spriteIsUnderwater(pSprite, false)) {
|
||||
|
@ -1056,7 +1050,7 @@ int aiDamageSprite(spritetype *pSprite, XSPRITE *pXSprite, int nSource, DAMAGE_T
|
|||
actKillDude(nSource, pSprite, DAMAGE_TYPE_0, 65535);
|
||||
}
|
||||
} else if (canWalk(pSprite) && !inDodge(pXSprite->aiState) && !inRecoil(pXSprite->aiState)) {
|
||||
if (inIdle(pXSprite->aiState) || inSearch(pXSprite->aiState) || Chance(getDodgeChance(pSprite))) {
|
||||
if (inIdle(pXSprite->aiState) || Chance(getDodgeChance(pSprite))) {
|
||||
if (!spriteIsUnderwater(pSprite, false)) {
|
||||
if (!canDuck(pSprite) || !sub_5BDA8(pSprite, 14)) aiGenDudeNewState(pSprite, &genDudeDodgeShortL);
|
||||
else aiGenDudeNewState(pSprite, &genDudeDodgeShortD);
|
||||
|
@ -1136,7 +1130,7 @@ void RecoilDude(spritetype *pSprite, XSPRITE *pXSprite)
|
|||
} 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 == 3) pXSprite->aiState->nextState = (Chance(rChance) ? &genDudeDodgeW : &genDudeDodgeShortW);
|
||||
|
||||
}
|
||||
else if (rState == 1) pXSprite->aiState->nextState = &genDudeChaseL;
|
||||
|
@ -1619,10 +1613,7 @@ void aiInitSprite(spritetype *pSprite)
|
|||
break;
|
||||
}
|
||||
case kDudeGillBeast:
|
||||
if (pXSector && pXSector->Underwater)
|
||||
aiNewState(pSprite, pXSprite, &gillBeastIdle);
|
||||
else
|
||||
aiNewState(pSprite, pXSprite, &gillBeastIdle);
|
||||
aiNewState(pSprite, pXSprite, &gillBeastIdle);
|
||||
break;
|
||||
case kDudeBat:
|
||||
{
|
||||
|
|
|
@ -89,6 +89,10 @@ AISTATE genDudeDodgeShortL = { kAiStateMove, 9, -1, 60, NULL, aiMoveDodge, NULL,
|
|||
AISTATE genDudeDodgeShortD = { kAiStateMove, 14, -1, 60, NULL, aiMoveDodge, NULL, &genDudeChaseD };
|
||||
AISTATE genDudeDodgeShortW = { kAiStateMove, 13, -1, 60, NULL, aiMoveDodge, NULL, &genDudeChaseW };
|
||||
// ---------------------
|
||||
AISTATE genDudeDodgeShorterL = { kAiStateMove, 9, -1, 20, NULL, aiMoveDodge, NULL, &genDudeChaseL };
|
||||
AISTATE genDudeDodgeShorterD = { kAiStateMove, 14, -1, 20, NULL, aiMoveDodge, NULL, &genDudeChaseD };
|
||||
AISTATE genDudeDodgeShorterW = { kAiStateMove, 13, -1, 20, NULL, aiMoveDodge, NULL, &genDudeChaseW };
|
||||
// ---------------------
|
||||
AISTATE genDudeChaseL = { kAiStateChase, 9, -1, 0, NULL, aiGenDudeMoveForward, thinkChase, NULL };
|
||||
AISTATE genDudeChaseD = { kAiStateChase, 14, -1, 0, NULL, aiGenDudeMoveForward, thinkChase, NULL };
|
||||
AISTATE genDudeChaseW = { kAiStateChase, 13, -1, 0, NULL, aiGenDudeMoveForward, thinkChase, NULL };
|
||||
|
@ -133,6 +137,40 @@ static void forcePunch(spritetype* pSprite, XSPRITE* pXSprite) {
|
|||
punchCallback(0,pSprite->extra);
|
||||
}
|
||||
|
||||
/*bool sameFamily(spritetype* pDude1, spritetype* pDude2) {
|
||||
|
||||
return true;
|
||||
}*/
|
||||
|
||||
bool genDudeAdjustSlope(spritetype* pSprite, XSPRITE* pXSprite, int dist, int weaponType, int by) {
|
||||
if (spriRangeIsFine(pXSprite->target)) {
|
||||
int fStart = 0; int fEnd = 0; GENDUDEEXTRA* pExtra = genDudeExtra(pSprite);
|
||||
|
||||
|
||||
for (int i = -8191; i < 8192; i += by) {
|
||||
HitScan(pSprite, pSprite->z, Cos(pSprite->ang) >> 16, Sin(pSprite->ang) >> 16, i, CLIPMASK0 | CLIPMASK1, dist);
|
||||
if (!fStart && pXSprite->target == gHitInfo.hitsprite) fStart = i;
|
||||
else if (fStart && pXSprite->target != gHitInfo.hitsprite) { fEnd = i; break; }
|
||||
}
|
||||
|
||||
if (fStart != fEnd) {
|
||||
|
||||
if (weaponType == kGenDudeWeaponHitscan)
|
||||
gDudeSlope[pSprite->extra] = fStart - ((fStart - fEnd) >> 2);
|
||||
else if (weaponType == kGenDudeWeaponMissile) {
|
||||
MissileType* pMissile = &missileInfo[pExtra->curWeapon - kMissileBase];
|
||||
gDudeSlope[pSprite->extra] = (fStart - ((fStart - fEnd) >> 2)) - (pMissile->clipDist << 1);
|
||||
}
|
||||
|
||||
//viewSetSystemMessage("!!!! FOUND, SLOPE %d, RANGE %d,%d", gDudeSlope[pSprite->extra], fStart, fEnd);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void genDudeProcess(spritetype* pSprite, XSPRITE* pXSprite) {
|
||||
GENDUDEEXTRA* pExtra = &gGenDudeExtra[pSprite->index];
|
||||
|
||||
|
@ -195,37 +233,35 @@ static void genDudeAttack1(int, int nXIndex) {
|
|||
}
|
||||
|
||||
XSPRITE* pXSprite = &xsprite[nXIndex]; int nSprite = pXSprite->reference;
|
||||
|
||||
if (!(nSprite >= 0 && nSprite < kMaxSprites)) {
|
||||
if (pXSprite->target < 0) return;
|
||||
else if (!(nSprite >= 0 && nSprite < kMaxSprites)) {
|
||||
consoleSysMsg("nIndex >= 0 && nIndex < kMaxSprites");
|
||||
return;
|
||||
}
|
||||
|
||||
spritetype* pSprite = &sprite[nSprite]; int dx, dy, dz;
|
||||
|
||||
int dx, dy, dz; spritetype* pSprite = &sprite[nSprite];
|
||||
xvel[pSprite->index] = yvel[pSprite->index] = 0;
|
||||
|
||||
short curWeapon = gGenDudeExtra[nSprite].curWeapon;
|
||||
|
||||
short dispersion = gGenDudeExtra[nSprite].baseDispersion;
|
||||
if (inDuck(pXSprite->aiState)) dispersion = ClipLow(dispersion >> 1, 250);
|
||||
if (inDuck(pXSprite->aiState))
|
||||
dispersion = ClipLow(dispersion >> 1, kGenDudeMinDispesion);
|
||||
|
||||
if (curWeapon >= 0 && curWeapon < kVectorMax) {
|
||||
//short dispersion = 1;
|
||||
|
||||
short curWeapon = gGenDudeExtra[nSprite].curWeapon; short weaponType = gGenDudeExtra[nSprite].weaponType;
|
||||
if (weaponType == kGenDudeWeaponHitscan) {
|
||||
|
||||
dx = Cos(pSprite->ang) >> 16; dy = Sin(pSprite->ang) >> 16; dz = gDudeSlope[nXIndex];
|
||||
|
||||
VECTORDATA* pVectorData = &gVectorData[curWeapon];
|
||||
int vdist = pVectorData->maxDist;
|
||||
|
||||
// dispersal modifiers here in case if non-melee enemy
|
||||
if (vdist <= 0 || vdist > 1280) {
|
||||
dx += Random3(dispersion); dy += Random3(dispersion);
|
||||
dz += Random3(dispersion);
|
||||
if (!dudeIsMelee(pXSprite)) {
|
||||
dx += Random3(dispersion); dy += Random3(dispersion); dz += Random3(dispersion);
|
||||
}
|
||||
|
||||
actFireVector(pSprite, 0, 0, dx, dy, dz,(VECTOR_TYPE)curWeapon);
|
||||
if (!playGenDudeSound(pSprite, kGenDudeSndAttackNormal))
|
||||
sfxPlayVectorSound(pSprite, curWeapon);
|
||||
|
||||
} else if (curWeapon >= kDudeBase && curWeapon < kDudeMax) {
|
||||
} else if (weaponType == kGenDudeWeaponSummon) {
|
||||
|
||||
spritetype* pSpawned = NULL; int dist = pSprite->clipdist << 4;
|
||||
short slaveCnt = gGenDudeExtra[pSprite->index].slaveCount;
|
||||
|
@ -247,15 +283,12 @@ static void genDudeAttack1(int, int nXIndex) {
|
|||
sfxPlay3DSoundCP(pSprite, 379, 1, 0, 0x10000 - Random3(0x3000));
|
||||
}
|
||||
|
||||
} else if (curWeapon >= kMissileBase && curWeapon < kMissileMax) {
|
||||
} else if (weaponType == kGenDudeWeaponMissile) {
|
||||
|
||||
dx = Cos(pSprite->ang) >> 16;
|
||||
dy = Sin(pSprite->ang) >> 16;
|
||||
dz = gDudeSlope[nXIndex];
|
||||
dx = Cos(pSprite->ang) >> 16; dy = Sin(pSprite->ang) >> 16; dz = gDudeSlope[nXIndex];
|
||||
|
||||
// dispersal modifiers here
|
||||
dx += Random3(dispersion); dy += Random3(dispersion);
|
||||
dz += Random3(dispersion >> 1);
|
||||
dx += Random3(dispersion); dy += Random3(dispersion); dz += Random3(dispersion >> 1);
|
||||
|
||||
actFireMissile(pSprite, 0, 0, dx, dy, dz, curWeapon);
|
||||
if (!playGenDudeSound(pSprite, kGenDudeSndAttackNormal))
|
||||
|
@ -282,13 +315,12 @@ static void ThrowThing(int nXIndex, bool impact) {
|
|||
return;
|
||||
|
||||
short curWeapon = gGenDudeExtra[sprite[pXSprite->reference].index].curWeapon;
|
||||
if (curWeapon < kThingBase || curWeapon >= kThingMax)
|
||||
return;
|
||||
short weaponType = gGenDudeExtra[sprite[pXSprite->reference].index].weaponType;
|
||||
if (weaponType != kGenDudeWeaponThrow) return;
|
||||
|
||||
const THINGINFO* pThinkInfo = &thingInfo[curWeapon - kThingBase];
|
||||
if (!pThinkInfo->allowThrow) return;
|
||||
|
||||
if (!playGenDudeSound(pSprite, kGenDudeSndAttackThrow))
|
||||
else if (!playGenDudeSound(pSprite, kGenDudeSndAttackThrow))
|
||||
sfxPlay3DSound(pSprite, 455, -1, 0);
|
||||
|
||||
int zThrow = 14500;
|
||||
|
@ -377,6 +409,10 @@ static void ThrowThing(int nXIndex, bool impact) {
|
|||
}
|
||||
|
||||
static void thinkSearch( spritetype* pSprite, XSPRITE* pXSprite ) {
|
||||
|
||||
// TO DO: if can't see the target, but in fireDist range - stop moving and look around
|
||||
|
||||
//viewSetSystemMessage("IN SEARCH");
|
||||
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
|
||||
sub_5F15C(pSprite, pXSprite);
|
||||
}
|
||||
|
@ -415,28 +451,23 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
spritetype* pTarget = &sprite[pXSprite->target];
|
||||
XSPRITE* pXTarget = (!IsDudeSprite(pTarget) || pTarget->extra < 0) ? NULL : &xsprite[pTarget->extra];
|
||||
XSPRITE* pXTarget = (!IsDudeSprite(pTarget) || !xspriRangeIsFine(pTarget->extra)) ? NULL : &xsprite[pTarget->extra];
|
||||
|
||||
if (pXTarget == NULL) { // target lost
|
||||
if(spriteIsUnderwater(pSprite,false)) aiGenDudeNewState(pSprite, &genDudeSearchShortW);
|
||||
else aiGenDudeNewState(pSprite, &genDudeSearchShortL);
|
||||
return;
|
||||
|
||||
} else if (pXTarget->health <= 0) { // target is dead
|
||||
PLAYER* pPlayer = NULL;
|
||||
if ((!IsPlayerSprite(pTarget) && pSprite->index == pTarget->owner)
|
||||
|| ((pPlayer = getPlayerById(pTarget->type)) != NULL && pPlayer->fraggerId == pSprite->index)) {
|
||||
|
||||
if ((!IsPlayerSprite(pTarget)) || ((pPlayer = getPlayerById(pTarget->type)) != NULL && pPlayer->fraggerId == pSprite->index)) {
|
||||
playGenDudeSound(pSprite, kGenDudeSndTargetDead);
|
||||
|
||||
if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeSearchShortW);
|
||||
else aiGenDudeNewState(pSprite, &genDudeSearchShortL);
|
||||
}
|
||||
else if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeGotoW);
|
||||
else aiGenDudeNewState(pSprite, &genDudeGotoL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -451,18 +482,17 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) {
|
|||
if (inAttack(pXSprite->aiState))
|
||||
xvelocity = yvelocity = ClipLow(pSprite->clipdist >> 1, 1);
|
||||
|
||||
//aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
|
||||
aiGenDudeChooseDirection(pSprite, pXSprite, getangle(dx, dy), xvelocity, yvelocity);
|
||||
|
||||
GENDUDEEXTRA* pExtra = &gGenDudeExtra[pSprite->index];
|
||||
if (!pExtra->canAttack) {
|
||||
aiSetTarget(pXSprite, pSprite->index);
|
||||
if (pExtra->canWalk) aiSetTarget(pXSprite, pSprite->index);
|
||||
if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeGotoW);
|
||||
else aiGenDudeNewState(pSprite, &genDudeGotoL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsPlayerSprite(pTarget)) {
|
||||
PLAYER* pPlayer = &gPlayer[ pTarget->type - kDudePlayer1 ];
|
||||
} else if (IsPlayerSprite(pTarget)) {
|
||||
PLAYER* pPlayer = &gPlayer[pTarget->type - kDudePlayer1];
|
||||
if (powerupCheck(pPlayer, kPwUpShadowCloak) > 0) {
|
||||
if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeSearchShortW);
|
||||
else aiGenDudeNewState(pSprite, &genDudeSearchShortL);
|
||||
|
@ -471,7 +501,9 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) {
|
|||
}
|
||||
|
||||
DUDEINFO* pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
|
||||
int eyeAboveZ = pDudeInfo->eyeHeight * pSprite->yrepeat << 2;
|
||||
int losAngle = ((getangle(dx, dy) + 1024 - pSprite->ang) & 2047) - 1024;
|
||||
int eyeAboveZ = (pDudeInfo->eyeHeight * pSprite->yrepeat) << 2;
|
||||
|
||||
if (dist > pDudeInfo->seeDist || !cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum,
|
||||
pSprite->x, pSprite->y, pSprite->z - eyeAboveZ, pSprite->sectnum)) {
|
||||
|
||||
|
@ -481,26 +513,25 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) {
|
|||
return;
|
||||
}
|
||||
|
||||
int nAngle = getangle(dx, dy);
|
||||
int losAngle = ((kAng180 + nAngle - pSprite->ang) & 2047) - kAng180;
|
||||
|
||||
// is the target visible?
|
||||
if (dist < pDudeInfo->seeDist && klabs(losAngle) <= pDudeInfo->periphery) {
|
||||
|
||||
if (((int)gFrameClock & 64) == 0 && Chance(0x3000) && !spriteIsUnderwater(pSprite, false))
|
||||
playGenDudeSound(pSprite, kGenDudeSndChasing);
|
||||
|
||||
gDudeSlope[sprite[pXSprite->reference].extra] = (int)divscale(pTarget->z - pSprite->z, dist, 10);
|
||||
|
||||
short curWeapon = gGenDudeExtra[pSprite->index].curWeapon;
|
||||
aiSetTarget(pXSprite, pXSprite->target);
|
||||
gDudeSlope[pSprite->extra] = divscale(pTarget->z - pSprite->z, dist, 10);
|
||||
|
||||
short curWeapon = gGenDudeExtra[pSprite->index].curWeapon; short weaponType = gGenDudeExtra[pSprite->index].weaponType;
|
||||
spritetype* pLeech = leechIsDropped(pSprite); VECTORDATA* meleeVector = &gVectorData[22];
|
||||
|
||||
if (pExtra->updReq[kGenDudePropertyAttack])
|
||||
genDudePrepare(pSprite, kGenDudePropertyAttack);
|
||||
|
||||
if (curWeapon >= kThingBase && curWeapon < kThingMax) {
|
||||
if (weaponType == kGenDudeWeaponThrow) {
|
||||
if (klabs(losAngle) < kAng15) {
|
||||
if (dist < 12264 && dist > 7680 && !spriteIsUnderwater(pSprite, false) && curWeapon != kModernThingEnemyLifeLeech) {
|
||||
if (!thingInfo[curWeapon - kThingBase].allowThrow) {
|
||||
if (spriteIsUnderwater(pSprite)) aiGenDudeNewState(pSprite, &genDudeChaseW);
|
||||
else aiGenDudeNewState(pSprite, &genDudeChaseL);
|
||||
return;
|
||||
|
||||
} else if (dist < 12264 && dist > 7680 && !spriteIsUnderwater(pSprite, false) && curWeapon != kModernThingEnemyLifeLeech) {
|
||||
int pHit = HitScan(pSprite, pSprite->z, dx, dy, 0, 16777280, 0);
|
||||
switch (pHit) {
|
||||
case 0:
|
||||
|
@ -575,16 +606,17 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) {
|
|||
|
||||
} else {
|
||||
|
||||
int defDist = gGenDudeExtra[pSprite->index].fireDist; int vdist = defDist;
|
||||
int vdist; int mdist; int defDist;
|
||||
defDist = vdist = mdist = gGenDudeExtra[pSprite->index].fireDist;
|
||||
|
||||
if (curWeapon > 0 && curWeapon < kVectorMax) {
|
||||
if ((vdist = gVectorData[curWeapon].maxDist) <= 0 || vdist > defDist)
|
||||
if (weaponType == kGenDudeWeaponHitscan) {
|
||||
if ((vdist = gVectorData[curWeapon].maxDist) <= 0)
|
||||
vdist = defDist;
|
||||
|
||||
} else if (curWeapon >= kDudeBase && curWeapon < kDudeMax) {
|
||||
} else if (weaponType == kGenDudeWeaponSummon) {
|
||||
|
||||
// don't attack slaves
|
||||
if (pXSprite->target >= 0 && sprite[pXSprite->target].owner == pSprite->xvel) {
|
||||
if (pXSprite->target >= 0 && sprite[pXSprite->target].owner == pSprite->index) {
|
||||
aiSetTarget(pXSprite, pSprite->x, pSprite->y, pSprite->z);
|
||||
return;
|
||||
} else if (gGenDudeExtra[pSprite->index].slaveCount > gGameOptions.nDifficulty || dist < meleeVector->maxDist) {
|
||||
|
@ -600,20 +632,23 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) {
|
|||
}
|
||||
}
|
||||
|
||||
} else if (curWeapon >= kMissileBase && curWeapon < kMissileMax) {
|
||||
} else if (weaponType == kGenDudeWeaponMissile) {
|
||||
// special handling for flame, explosive and life leech missiles
|
||||
int state = checkAttackState(pSprite, pXSprite);
|
||||
int mdist = (curWeapon != kMissileFlareAlt) ? 3000 : 2500;
|
||||
switch (curWeapon) {
|
||||
case kMissileLifeLeechRegular:
|
||||
// pickup life leech if it was thrown previously
|
||||
if (pLeech != NULL) removeLeech(pLeech);
|
||||
mdist = 1500;
|
||||
break;
|
||||
case kMissileFlareAlt:
|
||||
mdist = 2500;
|
||||
fallthrough__;
|
||||
case kMissileFireball:
|
||||
case kMissileFireballNapam:
|
||||
case kMissileFireballCerberus:
|
||||
case kMissileFireballTchernobog:
|
||||
if (mdist == defDist) mdist = 3000;
|
||||
if (dist > mdist || pXSprite->locked == 1) break;
|
||||
else if (dist <= meleeVector->maxDist && Chance(0x9000))
|
||||
aiGenDudeNewState(pSprite, &genDudePunch);
|
||||
|
@ -623,19 +658,23 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) {
|
|||
return;
|
||||
case kMissileFlameSpray:
|
||||
case kMissileFlameHound:
|
||||
//viewSetSystemMessage("%d", pXTarget->burnTime);
|
||||
if (spriteIsUnderwater(pSprite, false)) {
|
||||
if (dist > meleeVector->maxDist) aiGenDudeNewState(pSprite, &genDudeChaseW);
|
||||
else if (Chance(0x8000)) aiGenDudeNewState(pSprite, &genDudePunch);
|
||||
else aiGenDudeNewState(pSprite, &genDudeDodgeW);
|
||||
else aiGenDudeNewState(pSprite, &genDudeDodgeShortW);
|
||||
return;
|
||||
} else if (dist <= 4000 && pXTarget->burnTime >= 2000 && pXTarget->burnSource == pSprite->index) {
|
||||
if (dist > meleeVector->maxDist) aiGenDudeNewState(pSprite, &genDudeChaseL);
|
||||
else aiGenDudeNewState(pSprite, &genDudePunch);
|
||||
return;
|
||||
}
|
||||
|
||||
vdist = 4200; if (((int)gFrameClock & 16) == 0) vdist += Random(800);
|
||||
vdist = 3500 + (gGameOptions.nDifficulty * 400);
|
||||
break;
|
||||
}
|
||||
} else if (curWeapon >= kTrapExploder && curWeapon < (kTrapExploder + kExplodeMax) - 1) {
|
||||
} else if (weaponType == kGenDudeWeaponKamikaze) {
|
||||
int nType = curWeapon - kTrapExploder; EXPLOSION* pExpl = &explodeInfo[nType];
|
||||
if (CheckProximity(pSprite, pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pExpl->radius / 2)) {
|
||||
if (CheckProximity(pSprite, pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pExpl->radius >> 1)) {
|
||||
xvel[pSprite->xvel] = zvel[pSprite->xvel] = yvel[pSprite->xvel] = 0;
|
||||
if (doExplosion(pSprite, nType) && pXSprite->health > 0)
|
||||
actDamageSprite(pSprite->xvel, pSprite, DAMAGE_TYPE_3, 65535);
|
||||
|
@ -643,30 +682,235 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) {
|
|||
return;
|
||||
}
|
||||
|
||||
//if (dist <= vdist && pXSprite->aiState == &genDudeChaseD)
|
||||
//aiGenDudeNewState(pSprite, &genDudeChaseL);
|
||||
|
||||
int state = checkAttackState(pSprite, pXSprite);
|
||||
int kAngle = (dist <= 2048) ? kAngle = pDudeInfo->periphery : kAng5;
|
||||
int kAngle = (dudeIsMelee(pXSprite) || dist <= kGenDudeMaxMeleeDist) ? pDudeInfo->periphery : kGenDudeKlabsAng;
|
||||
|
||||
if (dist < vdist && klabs(losAngle) < kAngle) {
|
||||
if (pExtra->canWalk) {
|
||||
int objDist = -1; int targetDist = -1; int hit = -1;
|
||||
if (weaponType == kGenDudeWeaponHitscan)
|
||||
hit = HitScan(pSprite, pSprite->z, Cos(pSprite->ang) >> 16, Sin(pSprite->ang) >> 16, gDudeSlope[pSprite->extra], CLIPMASK1, dist);
|
||||
else if (weaponType == kGenDudeWeaponMissile)
|
||||
hit = HitScan(pSprite, pSprite->z, Cos(pSprite->ang) >> 16, Sin(pSprite->ang) >> 16, gDudeSlope[pSprite->extra], CLIPMASK0, dist);
|
||||
|
||||
if (hit >= 0) {
|
||||
targetDist = dist - (pTarget->clipdist << 2);
|
||||
objDist = approxDist(gHitInfo.hitx - pSprite->x, gHitInfo.hity - pSprite->y);
|
||||
}
|
||||
|
||||
if (pXSprite->target != gHitInfo.hitsprite && targetDist > objDist) {
|
||||
walltype* pHWall = NULL; XWALL* pXHWall = NULL;
|
||||
spritetype* pHSprite = NULL; XSPRITE* pXHSprite = NULL;
|
||||
bool hscn = false; bool blck = false; bool failed = false;
|
||||
|
||||
switch (hit) {
|
||||
case 3:
|
||||
pHSprite = &sprite[gHitInfo.hitsprite];
|
||||
if (xspriRangeIsFine(pHSprite->extra)) pXHSprite = &xsprite[pHSprite->extra];
|
||||
hscn = (pHSprite->cstat & CSTAT_SPRITE_BLOCK_HITSCAN); blck = (pHSprite->cstat & CSTAT_SPRITE_BLOCK);
|
||||
break;
|
||||
case 0:
|
||||
case 4:
|
||||
pHWall = &wall[gHitInfo.hitwall];
|
||||
if (xwallRangeIsFine(pHWall->extra)) pXHWall = &xwall[pHWall->extra];
|
||||
hscn = (pHWall->cstat & CSTAT_WALL_BLOCK_HITSCAN); blck = (pHWall->cstat & CSTAT_WALL_BLOCK);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (hit) {
|
||||
case 0:
|
||||
//if (hit == 0) viewSetSystemMessage("WALL HIT %d", gHitInfo.hitwall);
|
||||
fallthrough__;
|
||||
case 1:
|
||||
//if (hit == 1) viewSetSystemMessage("CEIL HIT %d", gHitInfo.hitsect);
|
||||
fallthrough__;
|
||||
case 2:
|
||||
if (hit == 2) viewSetSystemMessage("FLOOR HIT %d", gHitInfo.hitsect);
|
||||
if (weaponType != kGenDudeWeaponMissile && genDudeAdjustSlope(pSprite, pXSprite, dist, weaponType)
|
||||
&& dist < (int)(6000 + Random(2000)) && pExtra->baseDispersion < kGenDudeMaxDispersion >> 1) break;
|
||||
|
||||
else if (spriteIsUnderwater(pSprite)) aiGenDudeNewState(pSprite, &genDudeChaseW);
|
||||
else aiGenDudeNewState(pSprite, &genDudeChaseL);
|
||||
return;
|
||||
case 3:
|
||||
if (pHSprite->statnum == kStatFX || pHSprite->statnum == kStatProjectile || pHSprite->statnum == kStatDebris)
|
||||
break;
|
||||
if (IsDudeSprite(pHSprite) && (weaponType != kGenDudeWeaponHitscan || hscn)) {
|
||||
// dodge a bit in sides
|
||||
if (pXHSprite->target != pSprite->index) {
|
||||
if (pExtra->baseDispersion < 1024 && weaponType != kGenDudeWeaponMissile) {
|
||||
if (spriteIsUnderwater(pSprite)) aiGenDudeNewState(pSprite, &genDudeDodgeShorterW);
|
||||
else if (inDuck(pXSprite->aiState)) aiGenDudeNewState(pSprite, &genDudeDodgeShorterD);
|
||||
else aiGenDudeNewState(pSprite, &genDudeDodgeShorterL);
|
||||
}
|
||||
else if (spriteIsUnderwater(pSprite)) aiGenDudeNewState(pSprite, &genDudeDodgeShortW);
|
||||
else if (inDuck(pXSprite->aiState)) aiGenDudeNewState(pSprite, &genDudeDodgeShortD);
|
||||
else aiGenDudeNewState(pSprite, &genDudeDodgeShortL);
|
||||
|
||||
switch (pHSprite->type) {
|
||||
case kDudeModernCustom: // and make dude which could be hit to dodge too
|
||||
if (!dudeIsMelee(pXHSprite) && Chance(dist << 4)) {
|
||||
if (!inAttack(pXHSprite->aiState)) {
|
||||
if (spriteIsUnderwater(pHSprite)) aiGenDudeNewState(pHSprite, &genDudeDodgeShorterW);
|
||||
else if (inDuck(pXSprite->aiState)) aiGenDudeNewState(pHSprite, &genDudeDodgeShorterD);
|
||||
else aiGenDudeNewState(pHSprite, &genDudeDodgeShorterL);
|
||||
|
||||
// preferable in opposite sides
|
||||
if (Chance(0x8000)) {
|
||||
if (pXSprite->dodgeDir == 1) pXHSprite->dodgeDir = -1;
|
||||
else if (pXSprite->dodgeDir == -1) pXHSprite->dodgeDir = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (pSprite->x < pHSprite->x) {
|
||||
if (Chance(0x9000) && pTarget->x > pHSprite->x) pXSprite->dodgeDir = -1;
|
||||
else pXSprite->dodgeDir = 1;
|
||||
} else {
|
||||
if (Chance(0x9000) && pTarget->x > pHSprite->x) pXSprite->dodgeDir = 1;
|
||||
else pXSprite->dodgeDir = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (pSprite->x < pHSprite->x) {
|
||||
if (Chance(0x9000) && pTarget->x > pHSprite->x) pXSprite->dodgeDir = -1;
|
||||
else pXSprite->dodgeDir = 1;
|
||||
} else {
|
||||
if (Chance(0x9000) && pTarget->x > pHSprite->x) pXSprite->dodgeDir = 1;
|
||||
else pXSprite->dodgeDir = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
} else if (weaponType == kGenDudeWeaponHitscan && hscn) {
|
||||
if (genDudeAdjustSlope(pSprite, pXSprite, dist, weaponType)) break;
|
||||
VectorScan(pSprite, 0, 0, Cos(pSprite->ang) >> 16, Sin(pSprite->ang) >> 16, gDudeSlope[pSprite->extra], dist, 1);
|
||||
if (pXSprite->target == gHitInfo.hitsprite) break;
|
||||
|
||||
bool immune = isImmune(pHSprite, gVectorData[curWeapon].dmgType);
|
||||
if (!(pXHSprite != NULL && (!immune || (immune && pHSprite->statnum == kStatThing && pXHSprite->Vector)) && !pXHSprite->locked)) {
|
||||
|
||||
if ((approxDist(gHitInfo.hitx - pSprite->x, gHitInfo.hity - pSprite->y) <= 1500 && !blck)
|
||||
|| (dist <= (int)(pExtra->fireDist / ClipLow(Random(4), 1)))) {
|
||||
|
||||
//viewSetSystemMessage("GO CHASE");
|
||||
if (spriteIsUnderwater(pSprite)) aiGenDudeNewState(pSprite, &genDudeChaseW);
|
||||
else aiGenDudeNewState(pSprite, &genDudeChaseL);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
int wd1 = picWidth(pHSprite->picnum, pHSprite->xrepeat);
|
||||
int wd2 = picWidth(pSprite->picnum, pSprite->xrepeat);
|
||||
if (wd1 < (wd2 << 3)) {
|
||||
//viewSetSystemMessage("OBJ SIZE: %d DUDE SIZE: %d", wd1, wd2);
|
||||
if (spriteIsUnderwater(pSprite)) aiGenDudeNewState(pSprite, &genDudeDodgeShorterW);
|
||||
else if (inDuck(pXSprite->aiState)) aiGenDudeNewState(pSprite, &genDudeDodgeShorterD);
|
||||
else aiGenDudeNewState(pSprite, &genDudeDodgeShorterL);
|
||||
|
||||
if (pSprite->x < pHSprite->x) {
|
||||
if (Chance(0x3000) && pTarget->x > pHSprite->x) pXSprite->dodgeDir = -1;
|
||||
else pXSprite->dodgeDir = 1;
|
||||
} else {
|
||||
if (Chance(0x3000) && pTarget->x > pHSprite->x) pXSprite->dodgeDir = 1;
|
||||
else pXSprite->dodgeDir = -1;
|
||||
}
|
||||
|
||||
if (((gSpriteHit[pSprite->extra].hit & 0xc000) == 0x8000) || ((gSpriteHit[pSprite->extra].hit & 0xc000) == 0xc000)) {
|
||||
if (spriteIsUnderwater(pSprite)) aiGenDudeNewState(pSprite, &genDudeChaseW);
|
||||
else aiGenDudeNewState(pSprite, &genDudeChaseL);
|
||||
pXSprite->goalAng = Random(kAng360);
|
||||
//viewSetSystemMessage("WALL OR SPRITE TOUCH");
|
||||
}
|
||||
|
||||
} else {
|
||||
if (spriteIsUnderwater(pSprite)) aiGenDudeNewState(pSprite, &genDudeChaseW);
|
||||
else aiGenDudeNewState(pSprite, &genDudeChaseL);
|
||||
//viewSetSystemMessage("TOO BIG OBJECT TO DODGE!!!!!!!!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
fallthrough__;
|
||||
case 4:
|
||||
if (hit == 4 && weaponType == kGenDudeWeaponHitscan && hscn) {
|
||||
bool masked = (pHWall->cstat & CSTAT_WALL_MASKED);
|
||||
if (masked) VectorScan(pSprite, 0, 0, Cos(pSprite->ang) >> 16, Sin(pSprite->ang) >> 16, gDudeSlope[pSprite->extra], dist, 1);
|
||||
|
||||
//viewSetSystemMessage("WALL VHIT: %d", gHitInfo.hitwall);
|
||||
if ((pXSprite->target != gHitInfo.hitsprite) && (pHWall->type != kWallGib || !masked || pXHWall == NULL || !pXHWall->triggerVector || pXHWall->locked)) {
|
||||
if (spriteIsUnderwater(pSprite)) aiGenDudeNewState(pSprite, &genDudeChaseW);
|
||||
else aiGenDudeNewState(pSprite, &genDudeChaseL);
|
||||
return;
|
||||
}
|
||||
} else if (hit >= 3 && weaponType == kGenDudeWeaponMissile && blck) {
|
||||
switch (curWeapon) {
|
||||
case kMissileLifeLeechRegular:
|
||||
case kMissileTeslaAlt:
|
||||
case kMissileFlareAlt:
|
||||
case kMissileFireball:
|
||||
case kMissileFireballNapam:
|
||||
case kMissileFireballCerberus:
|
||||
case kMissileFireballTchernobog: {
|
||||
// allow attack if dude is far from object, but target is close to it
|
||||
int dudeDist = approxDist(gHitInfo.hitx - pSprite->x, gHitInfo.hity - pSprite->y);
|
||||
int targetDist = approxDist(gHitInfo.hitx - pTarget->x, gHitInfo.hity - pTarget->y);
|
||||
if (dudeDist < mdist) {
|
||||
//viewSetSystemMessage("DUDE CLOSE TO OBJ: %d, MDIST: %d", dudeDist, mdist);
|
||||
if (spriteIsUnderwater(pSprite)) aiGenDudeNewState(pSprite, &genDudeChaseW);
|
||||
else aiGenDudeNewState(pSprite, &genDudeChaseL);
|
||||
return;
|
||||
} else if (targetDist <= mdist >> 1) {
|
||||
//viewSetSystemMessage("TARGET CLOSE TO OBJ: %d, MDIST: %d", targetDist, mdist >> 1);
|
||||
break;
|
||||
}
|
||||
fallthrough__;
|
||||
}
|
||||
default:
|
||||
//viewSetSystemMessage("DEF HIT: %d, MDIST: %d", hit, mdist);
|
||||
if (hit == 4) failed = (pHWall->type != kWallGib || pXHWall == NULL || !pXHWall->triggerVector || pXHWall->locked);
|
||||
else if (hit == 3 && (failed = (pHSprite->statnum != kStatThing || pXHSprite == NULL || pXHSprite->locked)) == false) {
|
||||
// check also for damage resistance (all possible damages missile can use)
|
||||
for (int i = 0; i < kDmgMax; i++) {
|
||||
if (missileInfo[curWeapon - kMissileBase].dmgType[i] && (failed = isImmune(pHSprite, i)) == false)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
if (spriteIsUnderwater(pSprite)) aiGenDudeNewState(pSprite, &genDudeSearchW);
|
||||
else aiGenDudeNewState(pSprite, &genDudeSearchL);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case 1:
|
||||
aiGenDudeNewState(pSprite, &genDudeFireW);
|
||||
pXSprite->aiState->nextState = &genDudeFireW;
|
||||
return;
|
||||
break;
|
||||
case 2:
|
||||
aiGenDudeNewState(pSprite, &genDudeFireD);
|
||||
pXSprite->aiState->nextState = &genDudeFireD;
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
aiGenDudeNewState(pSprite, &genDudeFireL);
|
||||
pXSprite->aiState->nextState = &genDudeFireL;
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (seqGetID(3, pSprite->extra) == pXSprite->data2 + (state < 3) ? 8 : 6) {
|
||||
|
||||
if (seqGetID(3, pSprite->extra) == pXSprite->data2 + ((state < 3) ? 8 : 6)) {
|
||||
if (state == 1) pXSprite->aiState->nextState = &genDudeChaseW;
|
||||
else if (state == 2) pXSprite->aiState->nextState = &genDudeChaseD;
|
||||
else pXSprite->aiState->nextState = &genDudeChaseL;
|
||||
|
@ -713,16 +957,6 @@ int checkAttackState(spritetype* pSprite, XSPRITE* pXSprite) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool TargetNearThing(spritetype* pSprite, int thingType) {
|
||||
for ( int nSprite = headspritesect[pSprite->sectnum]; nSprite >= 0; nSprite = nextspritesect[nSprite] )
|
||||
{
|
||||
// check for required things or explosions in the same sector as the target
|
||||
if ( sprite[nSprite].type == thingType || sprite[nSprite].statnum == kStatExplosion )
|
||||
return true; // indicate danger
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
///// For gen dude
|
||||
int getGenDudeMoveSpeed(spritetype* pSprite,int which, bool mul, bool shift) {
|
||||
DUDEINFO* pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
|
||||
|
@ -802,7 +1036,7 @@ void aiGenDudeMoveForward(spritetype* pSprite, XSPRITE* pXSprite ) {
|
|||
int sin = Sin(pSprite->ang);
|
||||
int cos = Cos(pSprite->ang);
|
||||
|
||||
int frontSpeed = gGenDudeExtra[pSprite->index].frontSpeed;
|
||||
int frontSpeed = gGenDudeExtra[pSprite->index].moveSpeed;
|
||||
xvel[pSprite->xvel] += mulscale(cos, frontSpeed, 30);
|
||||
yvel[pSprite->xvel] += mulscale(sin, frontSpeed, 30);
|
||||
}
|
||||
|
@ -855,17 +1089,21 @@ void aiGenDudeNewState(spritetype* pSprite, AISTATE* pAIState) {
|
|||
// redirect dudes which cannot walk to non-walk states
|
||||
if (!gGenDudeExtra[pSprite->index].canWalk) {
|
||||
|
||||
if (pAIState == &genDudeDodgeL || pAIState == &genDudeDodgeShortL)
|
||||
if (pAIState == &genDudeDodgeL || pAIState == &genDudeDodgeShortL || pAIState == &genDudeDodgeShorterL)
|
||||
pAIState = &genDudeRecoilL;
|
||||
|
||||
else if (pAIState == &genDudeDodgeD || pAIState == &genDudeDodgeShortD)
|
||||
else if (pAIState == &genDudeDodgeD || pAIState == &genDudeDodgeShortD || pAIState == &genDudeDodgeShorterD)
|
||||
pAIState = &genDudeRecoilD;
|
||||
|
||||
else if (pAIState == &genDudeDodgeW || pAIState == &genDudeDodgeD)
|
||||
else if (pAIState == &genDudeDodgeW || pAIState == &genDudeDodgeShortW || pAIState == &genDudeDodgeShorterW)
|
||||
pAIState = &genDudeRecoilW;
|
||||
|
||||
else if (pAIState == &genDudeSearchL) pAIState = &genDudeSearchNoWalkL;
|
||||
else if (pAIState == &genDudeSearchW) pAIState = &genDudeSearchNoWalkW;
|
||||
else if (pAIState == &genDudeSearchL || pAIState == &genDudeSearchShortL)
|
||||
pAIState = &genDudeSearchNoWalkL;
|
||||
|
||||
else if (pAIState == &genDudeSearchW || pAIState == &genDudeSearchShortW)
|
||||
pAIState = &genDudeSearchNoWalkW;
|
||||
|
||||
else if (pAIState == &genDudeGotoL) pAIState = &genDudeIdleL;
|
||||
else if (pAIState == &genDudeGotoW) pAIState = &genDudeIdleW;
|
||||
else if (pAIState == &genDudeChaseL) pAIState = &genDudeChaseNoWalkL;
|
||||
|
@ -879,6 +1117,11 @@ void aiGenDudeNewState(spritetype* pSprite, AISTATE* pAIState) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
if (!gGenDudeExtra[pSprite->index].canRecoil) {
|
||||
if (pAIState == &genDudeRecoilL || pAIState == &genDudeRecoilD) pAIState = &genDudeIdleL;
|
||||
else if (pAIState == &genDudeRecoilW) pAIState = &genDudeIdleW;
|
||||
}
|
||||
|
||||
pXSprite->stateTimer = pAIState->stateTicks; pXSprite->aiState = pAIState;
|
||||
int seqStartId = pXSprite->data2;
|
||||
|
@ -892,7 +1135,7 @@ void aiGenDudeNewState(spritetype* pSprite, AISTATE* pAIState) {
|
|||
}
|
||||
|
||||
|
||||
bool playGenDudeSound(spritetype* pSprite, int mode, bool forceInterrupt) {
|
||||
bool playGenDudeSound(spritetype* pSprite, int mode) {
|
||||
|
||||
if (mode < kGenDudeSndTargetSpot || mode >= kGenDudeSndMax) return false;
|
||||
GENDUDESND* sndInfo =& gCustomDudeSnd[mode]; bool gotSnd = false;
|
||||
|
@ -912,7 +1155,6 @@ bool playGenDudeSound(spritetype* pSprite, int mode, bool forceInterrupt) {
|
|||
pExtra->sndPlaying = false;
|
||||
break;
|
||||
}
|
||||
//viewSetSystemMessage("PLAYING %d / %d / %d", Bonkle[i].atc, (sndId + a), Bonkle[i].at0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1050,26 +1292,28 @@ bool dudeIsMelee(XSPRITE* pXSprite) {
|
|||
void scaleDamage(XSPRITE* pXSprite) {
|
||||
|
||||
short curWeapon = gGenDudeExtra[sprite[pXSprite->reference].index].curWeapon;
|
||||
short* curScale = gGenDudeExtra[sprite[pXSprite->reference].index].dmgControl;
|
||||
short weaponType = gGenDudeExtra[sprite[pXSprite->reference].index].weaponType;
|
||||
unsigned short* curScale = gGenDudeExtra[sprite[pXSprite->reference].index].dmgControl;
|
||||
for (int i = 0; i < kDmgMax; i++)
|
||||
curScale[i] = dudeInfo[kDudeModernCustom - kDudeBase].startDamage[i];
|
||||
|
||||
// all enemies with vector weapons gets extra resistance to bullet damage
|
||||
if (curWeapon > 0 && curWeapon < kVectorMax) {
|
||||
//curScale[kDmgBullet] -= 10;
|
||||
if (weaponType == kGenDudeWeaponHitscan) {
|
||||
|
||||
curScale[kDmgBullet] -= 10;
|
||||
|
||||
// just copy damage resistance of dude that should be summoned
|
||||
} else if (curWeapon >= kDudeBase && curWeapon < kDudeMax) {
|
||||
} else if (weaponType == kGenDudeWeaponSummon) {
|
||||
|
||||
for (int i = 0; i < kDmgMax; i++)
|
||||
curScale[i] = dudeInfo[curWeapon - kDudeBase].startDamage[i];
|
||||
|
||||
// these does not like the explosions and burning
|
||||
} else if (curWeapon >= kTrapExploder && curWeapon < (kTrapExploder + kExplodeMax) - 1) {
|
||||
} else if (weaponType == kGenDudeWeaponKamikaze) {
|
||||
|
||||
curScale[kDmgBurn] = curScale[kDmgExplode] = 512;
|
||||
|
||||
} else if (curWeapon >= kMissileBase && curWeapon < kThingMax) {
|
||||
} else if (weaponType == kGenDudeWeaponMissile || weaponType == kGenDudeWeaponThrow) {
|
||||
|
||||
switch (curWeapon) {
|
||||
case kMissileButcherKnife:
|
||||
|
@ -1092,7 +1336,7 @@ void scaleDamage(XSPRITE* pXSprite) {
|
|||
case kThingPodFireBall:
|
||||
case kThingNapalmBall:
|
||||
curScale[kDmgBurn] = 32;
|
||||
curScale[kDmgExplode] = 50;
|
||||
curScale[kDmgExplode] -= 20;
|
||||
break;
|
||||
case kMissileLifeLeechRegular:
|
||||
case kThingDroppedLifeLeech:
|
||||
|
@ -1134,29 +1378,29 @@ void scaleDamage(XSPRITE* pXSprite) {
|
|||
switch (pXSprite->dropMsg) {
|
||||
case kItemArmorAsbest:
|
||||
curScale[kDmgBurn] = 0;
|
||||
curScale[kDmgExplode] -= 25;
|
||||
curScale[kDmgExplode] -= 30;
|
||||
break;
|
||||
case kItemArmorBasic:
|
||||
curScale[kDmgBurn] -= 10;
|
||||
curScale[kDmgExplode] -= 10;
|
||||
curScale[kDmgBullet] -= 10;
|
||||
curScale[kDmgSpirit] -= 10;
|
||||
curScale[kDmgBurn] -= 15;
|
||||
curScale[kDmgExplode] -= 15;
|
||||
curScale[kDmgBullet] -= 15;
|
||||
curScale[kDmgSpirit] -= 15;
|
||||
break;
|
||||
case kItemArmorBody:
|
||||
curScale[kDmgBullet] -= 20;
|
||||
curScale[kDmgBullet] -= 30;
|
||||
break;
|
||||
case kItemArmorFire:
|
||||
curScale[kDmgBurn] -= 20;
|
||||
curScale[kDmgExplode] -= 10;
|
||||
curScale[kDmgBurn] -= 30;
|
||||
curScale[kDmgExplode] -= 30;
|
||||
break;
|
||||
case kItemArmorSpirit:
|
||||
curScale[kDmgSpirit] -= 20;
|
||||
curScale[kDmgSpirit] -= 30;
|
||||
break;
|
||||
case kItemArmorSuper:
|
||||
curScale[kDmgBurn] -= 20;
|
||||
curScale[kDmgExplode] -= 20;
|
||||
curScale[kDmgBullet] -= 20;
|
||||
curScale[kDmgSpirit] -= 20;
|
||||
curScale[kDmgBurn] -= 60;
|
||||
curScale[kDmgExplode] -= 60;
|
||||
curScale[kDmgBullet] -= 60;
|
||||
curScale[kDmgSpirit] -= 60;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1240,13 +1484,9 @@ void scaleDamage(XSPRITE* pXSprite) {
|
|||
for (int i = 0; i < kDmgMax; i++)
|
||||
curScale[i] = mulscale8(DudeDifficulty[gGameOptions.nDifficulty], ClipLow(curScale[i], 1));
|
||||
|
||||
short* dc = curScale;
|
||||
if (gGenDudeExtra[sprite[pXSprite->reference].index].canFly) {
|
||||
curScale[0] = -1;
|
||||
}
|
||||
|
||||
if (pXSprite->rxID == 788)
|
||||
viewSetSystemMessage("0: %d, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d, 6: %d", dc[0], dc[1], dc[2], dc[3], dc[4], dc[5], dc[6]);
|
||||
//short* dc = curScale;
|
||||
//if (pXSprite->rxID == 788)
|
||||
//viewSetSystemMessage("0: %d, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d, 6: %d", dc[0], dc[1], dc[2], dc[3], dc[4], dc[5], dc[6]);
|
||||
}
|
||||
|
||||
int getDispersionModifier(spritetype* pSprite, int minDisp, int maxDisp) {
|
||||
|
@ -1260,7 +1500,7 @@ int getDispersionModifier(spritetype* pSprite, int minDisp, int maxDisp) {
|
|||
|
||||
disp = (((shots * 1000) / nFrames) / ticks) * 20;
|
||||
if (gGameOptions.nDifficulty > 0)
|
||||
disp /= gGameOptions.nDifficulty + 1;
|
||||
disp /= gGameOptions.nDifficulty;
|
||||
|
||||
//viewSetSystemMessage("DISP: %d FRAMES: %d SHOTS: %d TICKS %d", disp, nFrames, shots, ticks);
|
||||
|
||||
|
@ -1282,8 +1522,8 @@ int getRangeAttackDist(spritetype* pSprite, int minDist, int maxDist) {
|
|||
picnum = seqGetTile(&pSeq->frames[0]);
|
||||
}
|
||||
}
|
||||
dist = tilesiz[picnum].y << 8;
|
||||
|
||||
dist = tilesiz[picnum].y << 8;
|
||||
if (yrepeat < 64) dist -= (64 - yrepeat) * mul;
|
||||
else if (yrepeat > 64) dist += (yrepeat - 64) * (mul / 3);
|
||||
}
|
||||
|
@ -1299,7 +1539,7 @@ int getBaseChanceModifier(int baseChance) {
|
|||
|
||||
int getRecoilChance(spritetype* pSprite) {
|
||||
XSPRITE* pXSprite = &xsprite[pSprite->extra]; int mass = getSpriteMassBySize(pSprite);
|
||||
int baseChance = (!dudeIsMelee(pXSprite) ? 0x8000 : 0x5000);
|
||||
int baseChance = (!dudeIsMelee(pXSprite) ? 0x8000 : 0x4000);
|
||||
baseChance = getBaseChanceModifier(baseChance) + pXSprite->data3;
|
||||
|
||||
int chance = ((baseChance / mass) << 7);
|
||||
|
@ -1307,16 +1547,13 @@ int getRecoilChance(spritetype* pSprite) {
|
|||
}
|
||||
|
||||
int getDodgeChance(spritetype* pSprite) {
|
||||
int mass = getSpriteMassBySize(pSprite); int baseChance = getBaseChanceModifier(0x6000);
|
||||
if (pSprite->extra >= 0) {
|
||||
XSPRITE* pXSprite = &xsprite[pSprite->extra];
|
||||
baseChance += pXSprite->burnTime;
|
||||
if (dudeIsMelee(pXSprite))
|
||||
baseChance = 0x1000;
|
||||
}
|
||||
XSPRITE* pXSprite = &xsprite[pSprite->extra]; int mass = getSpriteMassBySize(pSprite);
|
||||
int baseChance = (!dudeIsMelee(pXSprite) ? 0x6000 : 0x1000);
|
||||
baseChance = getBaseChanceModifier(baseChance) + pXSprite->data3;
|
||||
|
||||
int chance = ((baseChance / mass) << 7);
|
||||
return chance;
|
||||
|
||||
}
|
||||
|
||||
void dudeLeechOperate(spritetype* pSprite, XSPRITE* pXSprite, EVENT event)
|
||||
|
@ -1327,7 +1564,7 @@ void dudeLeechOperate(spritetype* pSprite, XSPRITE* pXSprite, EVENT event)
|
|||
}
|
||||
|
||||
int nTarget = pXSprite->target;
|
||||
if (spriRangeIsFine(nTarget)) {
|
||||
if (spriRangeIsFine(nTarget) && nTarget != pSprite->owner) {
|
||||
spritetype* pTarget = &sprite[nTarget];
|
||||
if (pTarget->statnum == kStatDude && !(pTarget->flags & 32) && pTarget->extra > 0 && pTarget->extra < kMaxXSprites && !pXSprite->stateTimer) {
|
||||
|
||||
|
@ -1465,8 +1702,18 @@ void updateTargetOfSlaves(spritetype* pSprite) {
|
|||
}
|
||||
}
|
||||
|
||||
bool inDodge(AISTATE* aiState) {
|
||||
return (aiState == &genDudeDodgeShortW || aiState == &genDudeDodgeShortL || aiState == &genDudeDodgeShortD);
|
||||
short inDodge(AISTATE* aiState) {
|
||||
if (aiState == &genDudeDodgeL) return 1;
|
||||
else if (aiState == &genDudeDodgeD) return 2;
|
||||
else if (aiState == &genDudeDodgeW) return 3;
|
||||
else if (aiState == &genDudeDodgeShortL) return 4;
|
||||
else if (aiState == &genDudeDodgeShortD) return 5;
|
||||
else if (aiState == &genDudeDodgeShortW) return 6;
|
||||
else if (aiState == &genDudeDodgeShorterL) return 7;
|
||||
else if (aiState == &genDudeDodgeShorterD) return 8;
|
||||
else if (aiState == &genDudeDodgeShorterW) return 9;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
bool inIdle(AISTATE* aiState) {
|
||||
|
@ -1483,6 +1730,16 @@ short inSearch(AISTATE* aiState) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
short inChase(AISTATE* aiState) {
|
||||
if (aiState == &genDudeChaseL) return 1;
|
||||
else if (aiState == &genDudeChaseD) return 2;
|
||||
else if (aiState == &genDudeChaseW) return 3;
|
||||
else if (aiState == &genDudeChaseNoWalkL) return 4;
|
||||
else if (aiState == &genDudeChaseNoWalkD) return 5;
|
||||
else if (aiState == &genDudeChaseNoWalkW) return 6;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
short inRecoil(AISTATE* aiState) {
|
||||
if (aiState == &genDudeRecoilL || aiState == &genDudeRecoilTesla) return 1;
|
||||
else if (aiState == &genDudeRecoilD) return 2;
|
||||
|
@ -1512,7 +1769,6 @@ bool canWalk(spritetype* pSprite) {
|
|||
return gGenDudeExtra[pSprite->index].canWalk;
|
||||
}
|
||||
|
||||
|
||||
int genDudeSeqStartId(XSPRITE* pXSprite) {
|
||||
if (genDudePrepare(&sprite[pXSprite->reference], kGenDudePropertyStates)) return pXSprite->data2;
|
||||
else return kGenDudeDefaultSeq;
|
||||
|
@ -1539,11 +1795,13 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
|
|||
switch (propId) {
|
||||
case kGenDudePropertyAll:
|
||||
case kGenDudePropertyInitVals:
|
||||
pExtra->frontSpeed = getGenDudeMoveSpeed(pSprite, 0, true, false);
|
||||
pExtra->moveSpeed = getGenDudeMoveSpeed(pSprite, 0, true, false);
|
||||
pExtra->initVals[0] = pSprite->xrepeat;
|
||||
pExtra->initVals[1] = pSprite->yrepeat;
|
||||
pExtra->initVals[2] = pSprite->clipdist;
|
||||
if (propId) break;
|
||||
fallthrough__;
|
||||
|
||||
case kGenDudePropertyWeapon: {
|
||||
pExtra->curWeapon = pXSprite->data1;
|
||||
switch (pXSprite->data1) {
|
||||
|
@ -1556,38 +1814,52 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
|
|||
if (pExtra->curWeapon > 0 && gSysRes.Lookup(pXSprite->data2 + kGenDudeSeqAttackNormalL, "SEQ"))
|
||||
pExtra->canAttack = true;
|
||||
|
||||
pExtra->weaponType = kGenDudeWeaponNone;
|
||||
if (pExtra->curWeapon > 0 && pExtra->curWeapon < kVectorMax) pExtra->weaponType = kGenDudeWeaponHitscan;
|
||||
else if (pExtra->curWeapon >= kDudeBase && pExtra->curWeapon < kDudeMax) pExtra->weaponType = kGenDudeWeaponSummon;
|
||||
else if (pExtra->curWeapon >= kMissileBase && pExtra->curWeapon < kMissileMax) pExtra->weaponType = kGenDudeWeaponMissile;
|
||||
else if (pExtra->curWeapon >= kThingBase && pExtra->curWeapon < kThingMax) pExtra->weaponType = kGenDudeWeaponThrow;
|
||||
else if (pExtra->curWeapon >= kTrapExploder && pExtra->curWeapon < (kTrapExploder + kExplodeMax) - 1)
|
||||
pExtra->weaponType = kGenDudeWeaponKamikaze;
|
||||
|
||||
pExtra->isMelee = false;
|
||||
if (pExtra->curWeapon >= kTrapExploder && pExtra->curWeapon < (kTrapExploder + kExplodeMax) - 1) pExtra->isMelee = true;
|
||||
else if (pExtra->curWeapon >= 0 && pExtra->curWeapon < kVectorMax) {
|
||||
if (pExtra->weaponType == kGenDudeWeaponKamikaze) pExtra->isMelee = true;
|
||||
else if (pExtra->weaponType == kGenDudeWeaponHitscan) {
|
||||
if (gVectorData[pExtra->curWeapon].maxDist > 0 && gVectorData[pExtra->curWeapon].maxDist <= kGenDudeMaxMeleeDist)
|
||||
pExtra->isMelee = true;
|
||||
}
|
||||
|
||||
if (propId) break;
|
||||
fallthrough__;
|
||||
|
||||
}
|
||||
case kGenDudePropertyDmgScale:
|
||||
scaleDamage(pXSprite);
|
||||
if (propId) break;
|
||||
fallthrough__;
|
||||
|
||||
case kGenDudePropertyMass: {
|
||||
// to ensure mass get's updated, let's clear all cache
|
||||
// to ensure mass gets updated, let's clear all cache
|
||||
SPRITEMASS* pMass = &gSpriteMass[pSprite->index];
|
||||
pMass->seqId = pMass->picnum = pMass->xrepeat = pMass->yrepeat = pMass->clipdist = 0;
|
||||
pMass->mass = pMass->airVel = pMass->fraction = 0;
|
||||
|
||||
getSpriteMassBySize(pSprite);
|
||||
if (propId) break;
|
||||
fallthrough__;
|
||||
}
|
||||
case kGenDudePropertyAttack:
|
||||
pExtra->fireDist = getRangeAttackDist(pSprite, 1200, 45000);
|
||||
pExtra->throwDist = pExtra->fireDist; // temp
|
||||
pExtra->baseDispersion = getDispersionModifier(pSprite, 200, 3500);
|
||||
if (propId) break;
|
||||
fallthrough__;
|
||||
|
||||
case kGenDudePropertyStates: {
|
||||
|
||||
pExtra->canFly = false;
|
||||
|
||||
// check the animation
|
||||
int seqStartId = dudeInfo[pSprite->type - kDudeBase].seqStartID;
|
||||
int seqStartId = -1;
|
||||
if (pXSprite->data2 <= 0) seqStartId = pXSprite->data2 = dudeInfo[pSprite->type - kDudeBase].seqStartID;
|
||||
else seqStartId = pXSprite->data2;
|
||||
|
||||
|
@ -1595,18 +1867,26 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
|
|||
switch (i - seqStartId) {
|
||||
case kGenDudeSeqIdleL:
|
||||
case kGenDudeSeqDeathDefault:
|
||||
case kGenDudeSeqAttackNormalL:
|
||||
case kGenDudeSeqAttackThrow:
|
||||
case kGenDudeSeqAttackPunch:
|
||||
if (!gSysRes.Lookup(i, "SEQ")) {
|
||||
pXSprite->data2 = dudeInfo[pSprite->type - kDudeBase].seqStartID;
|
||||
viewSetSystemMessage("No SEQ animation id %d found for custom dude #%d!", i, pSprite->index);
|
||||
viewSetSystemMessage("SEQ base id: %d", seqStartId);
|
||||
} else if ((i - seqStartId) == kGenDudeSeqAttackPunch) {
|
||||
pExtra->forcePunch = true; // required for those who don't have fire trigger in punch seq and for default animation
|
||||
Seq* pSeq = NULL; DICTNODE* hSeq = gSysRes.Lookup(i, "SEQ");
|
||||
pSeq = (Seq*)gSysRes.Load(hSeq);
|
||||
for (int i = 0; i < pSeq->nFrames; i++) {
|
||||
if (!pSeq->frames[i].at5_5) continue;
|
||||
pExtra->forcePunch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kGenDudeSeqDeathExplode:
|
||||
if (gSysRes.Lookup(i, "SEQ")) pExtra->availDeaths[kDmgExplode] = 1;
|
||||
else pExtra->availDeaths[kDmgExplode] = 0;
|
||||
break;
|
||||
case kGenDudeSeqAttackNormalL:
|
||||
pExtra->canAttack = (gSysRes.Lookup(i, "SEQ") && pExtra->curWeapon > 0);
|
||||
pExtra->availDeaths[kDmgExplode] = (bool)gSysRes.Lookup(i, "SEQ");
|
||||
break;
|
||||
case kGenDudeSeqBurning:
|
||||
pExtra->canBurn = gSysRes.Lookup(i, "SEQ");
|
||||
|
@ -1636,19 +1916,6 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case kGenDudeSeqAttackPunch: {
|
||||
pExtra->forcePunch = true; // required for those who don't have fire trigger in punch seq and for default animation
|
||||
Seq* pSeq = NULL; DICTNODE* hSeq = gSysRes.Lookup(i, "SEQ");
|
||||
if (hSeq != NULL) {
|
||||
pSeq = (Seq*)gSysRes.Load(hSeq);
|
||||
for (int i = 0; i < pSeq->nFrames; i++) {
|
||||
if (!pSeq->frames[i].at5_5) continue;
|
||||
pExtra->forcePunch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kGenDudeSeqAttackNormalDW:
|
||||
pExtra->canDuck = (gSysRes.Lookup(i, "SEQ") && gSysRes.Lookup(seqStartId + 14, "SEQ"));
|
||||
pExtra->canSwim = (gSysRes.Lookup(i, "SEQ") && gSysRes.Lookup(seqStartId + 13, "SEQ")
|
||||
|
@ -1682,9 +1949,9 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
|
|||
}
|
||||
}
|
||||
if (propId) break;
|
||||
fallthrough__;
|
||||
}
|
||||
case kGenDudePropertyLeech:
|
||||
//viewSetSystemMessage("PROPERTY: LEECH");
|
||||
pExtra->nLifeLeech = -1;
|
||||
if (pSprite->owner != kMaxSprites - 1) {
|
||||
for (int nSprite = headspritestat[kStatThing]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
|
||||
|
@ -1695,8 +1962,9 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
|
|||
}
|
||||
}
|
||||
if (propId) break;
|
||||
fallthrough__;
|
||||
|
||||
case kGenDudePropertySlaves:
|
||||
//viewSetSystemMessage("PROPERTY: SLAVES");
|
||||
pExtra->slaveCount = 0; memset(pExtra->slave, -1, sizeof(pExtra->slave));
|
||||
for (int nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
|
||||
if (sprite[nSprite].owner != pSprite->xvel) continue;
|
||||
|
@ -1710,6 +1978,8 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
|
|||
break;
|
||||
}
|
||||
if (propId) break;
|
||||
fallthrough__;
|
||||
|
||||
case kGenDudePropertySpriteSize: {
|
||||
if (seqGetStatus(3, pSprite->extra) == -1)
|
||||
seqSpawn(pXSprite->data2 + pXSprite->aiState->seqId, 3, pSprite->extra, -1);
|
||||
|
@ -1727,6 +1997,7 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
|
|||
else pSprite->clipdist = pExtra->initVals[2];
|
||||
|
||||
if (propId) break;
|
||||
fallthrough__;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,9 @@ BEGIN_BLD_NS
|
|||
#define kGenDudeTransformStatus -222
|
||||
#define kGenDudeUpdTimeRate 10
|
||||
#define kGenDudeMaxMeleeDist 2048
|
||||
#define kGenDudeMinDispesion 200
|
||||
#define kGenDudeMaxDispersion 3500
|
||||
#define kGenDudeKlabsAng 56
|
||||
|
||||
enum {
|
||||
kGenDudeSeqIdleL = 0,
|
||||
|
@ -90,6 +93,16 @@ kGenDudePropertyInitVals = 9,
|
|||
kGenDudePropertyMax ,
|
||||
};
|
||||
|
||||
enum {
|
||||
kGenDudeWeaponNone = -1,
|
||||
kGenDudeWeaponHitscan = 0,
|
||||
kGenDudeWeaponMissile = 1,
|
||||
kGenDudeWeaponThrow = 2,
|
||||
kGenDudeWeaponSummon = 3,
|
||||
kGenDudeWeaponKamikaze = 4,
|
||||
kGenDudeWeaponMax ,
|
||||
};
|
||||
|
||||
extern AISTATE genDudeIdleL;
|
||||
extern AISTATE genDudeIdleW;
|
||||
extern AISTATE genDudeSearchL;
|
||||
|
@ -102,6 +115,9 @@ extern AISTATE genDudeDodgeW;
|
|||
extern AISTATE genDudeDodgeShortL;
|
||||
extern AISTATE genDudeDodgeShortD;
|
||||
extern AISTATE genDudeDodgeShortW;
|
||||
extern AISTATE genDudeDodgeShorterL;
|
||||
extern AISTATE genDudeDodgeShorterD;
|
||||
extern AISTATE genDudeDodgeShorterW;
|
||||
extern AISTATE genDudeChaseL;
|
||||
extern AISTATE genDudeChaseD;
|
||||
extern AISTATE genDudeChaseW;
|
||||
|
@ -134,20 +150,21 @@ extern GENDUDESND gCustomDudeSnd[];
|
|||
|
||||
// temporary, until normal DUDEEXTRA gets refactored
|
||||
struct GENDUDEEXTRA {
|
||||
unsigned short initVals[3]; // xrepeat, yrepeat, clipdist
|
||||
unsigned short availDeaths[kDamageMax]; // list of seqs with deaths for each damage type
|
||||
unsigned short dmgControl[kDamageMax]; // depends of current weapon, drop armor item, sprite yrepeat and surface type
|
||||
unsigned int moveSpeed;
|
||||
unsigned int fireDist; // counts from sprite size
|
||||
unsigned int throwDist; // counts from sprite size
|
||||
unsigned int frontSpeed;
|
||||
unsigned short curWeapon; // data1 duplicate to avoid potential problems when changing data dynamically
|
||||
unsigned short weaponType;
|
||||
unsigned short baseDispersion;
|
||||
unsigned short slaveCount; // how many dudes is summoned
|
||||
signed short nLifeLeech; // spritenum of dropped dude's leech
|
||||
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
|
||||
signed short slave[kGenDudeMaxSlaves]; // index of the ones dude is summon
|
||||
bool updReq[kGenDudePropertyMax]; // update requests
|
||||
bool sndPlaying; // indicate if sound of AISTATE currently playing
|
||||
bool forcePunch; // indicate if there is no fire trigger in punch state seq
|
||||
bool isMelee;
|
||||
bool canBurn; // can turn in Burning dude or not
|
||||
bool canElectrocute;
|
||||
|
@ -171,12 +188,11 @@ void removeLeech(spritetype* pLeech, bool delSprite = true);
|
|||
void removeDudeStuff(spritetype* pSprite);
|
||||
spritetype* leechIsDropped(spritetype* pSprite);
|
||||
bool spriteIsUnderwater(spritetype* pSprite, bool oldWay = false);
|
||||
bool playGenDudeSound(spritetype* pSprite, int mode, bool forceInterrupt = false);
|
||||
bool playGenDudeSound(spritetype* pSprite, int mode);
|
||||
void aiGenDudeMoveForward(spritetype* pSprite, XSPRITE* pXSprite);
|
||||
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);
|
||||
bool TargetNearThing(spritetype* pSprite, int thingType);
|
||||
int checkAttackState(spritetype* pSprite, XSPRITE* pXSprite);
|
||||
bool doExplosion(spritetype* pSprite, int nType);
|
||||
void dudeLeechOperate(spritetype* pSprite, XSPRITE* pXSprite, EVENT a3);
|
||||
|
@ -188,11 +204,12 @@ void updateTargetOfLeech(spritetype* pSprite);
|
|||
bool canSwim(spritetype* pSprite);
|
||||
bool canDuck(spritetype* pSprite);
|
||||
bool canWalk(spritetype* pSprite);
|
||||
bool inDodge(AISTATE* aiState);
|
||||
short inDodge(AISTATE* aiState);
|
||||
bool inIdle(AISTATE* aiState);
|
||||
bool inAttack(AISTATE* aiState);
|
||||
short inRecoil(AISTATE* aiState);
|
||||
short inSearch(AISTATE* aiState);
|
||||
short inChase(AISTATE* aiState);
|
||||
short inDuck(AISTATE* aiState);
|
||||
int genDudeSeqStartId(XSPRITE* pXSprite);
|
||||
int getRangeAttackDist(spritetype* pSprite, int minDist = 1200, int maxDist = 80000);
|
||||
|
@ -201,5 +218,5 @@ void scaleDamage(XSPRITE* pXSprite);
|
|||
bool genDudePrepare(spritetype* pSprite, int propId = kGenDudePropertyAll);
|
||||
void genDudeUpdate(spritetype* pSprite);
|
||||
void genDudeProcess(spritetype* pSprite, XSPRITE* pXSprite);
|
||||
|
||||
bool genDudeAdjustSlope(spritetype* pSprite, XSPRITE* pXSprite, int dist, int weaponType, int by = 64);
|
||||
END_BLD_NS
|
||||
|
|
|
@ -135,7 +135,8 @@ void ambInit(void)
|
|||
auto snd = soundEngine->FindSoundByResID(nSFX);
|
||||
if (!snd) {
|
||||
//ThrowError("Missing sound #%d used in ambient sound generator %d\n", nSFX);
|
||||
viewSetSystemMessage("Missing sound #%d used in ambient sound generator #%d\n", nSFX);
|
||||
viewSetSystemMessage("Missing sound #%d used in ambient sound generator #%d\n", nSFX, nSprite);
|
||||
actPostSprite(nSprite, kStatDecoration);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -605,10 +605,6 @@ void StartLevel(GAMEOPTIONS *gameOptions)
|
|||
pSprite->type = kSpriteDecoration;
|
||||
changespritestat(pSprite->index, kStatDecoration);
|
||||
break;
|
||||
case kModernConcussSprite:
|
||||
pSprite->type = kSpriteDecoration;
|
||||
changespritestat(pSprite->index, kStatDecoration);
|
||||
break;
|
||||
// also erase some modernized vanilla types which was not active
|
||||
case kMarkerWarpDest:
|
||||
if (pSprite->statnum != kStatMarker) pSprite->type = kSpriteDecoration;
|
||||
|
|
|
@ -346,7 +346,9 @@ void CounterCheck(int nSector) // 12
|
|||
|
||||
// By NoOne: remove check below, so every sector can be counter if command 12 (this callback) received.
|
||||
//if (pSector->type != kSectorCounter) return;
|
||||
if (sector[nSector].extra <= 0) return; XSECTOR *pXSector = &xsector[sector[nSector].extra];
|
||||
if (sector[nSector].extra <= 0) return;
|
||||
|
||||
XSECTOR *pXSector = &xsector[sector[nSector].extra];
|
||||
int nReq = pXSector->waitTimeA; int nType = pXSector->data; int nCount = 0;
|
||||
if (!nType || !nReq) return;
|
||||
|
||||
|
|
|
@ -88,6 +88,8 @@ void _consoleSysMsg(const char* pMessage, ...);
|
|||
#define kMaxPAL 5
|
||||
#define kFreeQAVEntry 108
|
||||
|
||||
#define kUserPLUStart 15
|
||||
|
||||
#define kDmgFall 0
|
||||
#define kDmgBurn 1
|
||||
#define kDmgBullet 2
|
||||
|
@ -197,7 +199,6 @@ enum {
|
|||
kModernObjDataAccumulator = 37,
|
||||
kModernEffectSpawner = 38,
|
||||
kModernWindGenerator = 39,
|
||||
kModernConcussSprite = 712, /// WIP
|
||||
kModernPlayerControl = 500, /// WIP
|
||||
|
||||
// decorations
|
||||
|
|
|
@ -44,10 +44,6 @@ inline bool xwallRangeIsFine(int nXindex) {
|
|||
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;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
|
|
@ -1546,30 +1546,30 @@ DUDEINFO dudeInfo[kDudeMax-kDudeBase] =
|
|||
},
|
||||
//254 - kDudeModernCustom
|
||||
{
|
||||
11520, // start sequence ID
|
||||
85, // start health
|
||||
75, // mass
|
||||
11520, // start sequence ID
|
||||
85, // start health
|
||||
75, // mass
|
||||
120,
|
||||
48, // clip distance
|
||||
48, // eye above z
|
||||
48, // clip distance
|
||||
48, // eye above z
|
||||
20,
|
||||
10240, // hear distance
|
||||
51200, // seeing distance
|
||||
kAng120, // vision periphery
|
||||
10240, // hear distance
|
||||
51200, // seeing distance
|
||||
kAng120, // vision periphery
|
||||
// 0,
|
||||
618, // melee distance
|
||||
5, // flee health
|
||||
5, // hinder damage
|
||||
0x0100, // change target chance
|
||||
0x0010, // change target to kin chance
|
||||
0x8000, // alertChance
|
||||
0, // lockout
|
||||
46603, // frontSpeed
|
||||
34952, // sideSpeed
|
||||
13981, // backSpeed
|
||||
256, // angSpeed
|
||||
618, // melee distance
|
||||
5, // flee health
|
||||
5, // hinder damage
|
||||
0x0100, // change target chance
|
||||
0x0010, // change target to kin chance
|
||||
0x8000, // alertChance
|
||||
0, // lockout
|
||||
46603, // frontSpeed
|
||||
34952, // sideSpeed
|
||||
13981, // backSpeed
|
||||
256, // angSpeed
|
||||
// 0,
|
||||
7, -1, 18, // nGibType
|
||||
7, -1, 18, // nGibType
|
||||
128, 150, 128, 256, 128, 128, 128,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
|
|
|
@ -356,12 +356,14 @@ void evSend(int nIndex, int nType, int rxId, COMMAND_ID command, short causedBy)
|
|||
EVENT event; event.index = nIndex; event.type = nType; event.cmd = command; event.causedBy = causedBy;
|
||||
|
||||
switch (command) {
|
||||
case kCmdState:
|
||||
command = evGetSourceState(nType, nIndex) ? kCmdOn : kCmdOff;
|
||||
break;
|
||||
case kCmdNotState:
|
||||
command = evGetSourceState(nType, nIndex) ? kCmdOff : kCmdOn;
|
||||
break;
|
||||
case kCmdState:
|
||||
command = evGetSourceState(nType, nIndex) ? kCmdOn : kCmdOff;
|
||||
break;
|
||||
case kCmdNotState:
|
||||
command = evGetSourceState(nType, nIndex) ? kCmdOff : kCmdOn;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (rxId) {
|
||||
|
|
|
@ -908,4 +908,12 @@ int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, short *pSector
|
|||
return n;
|
||||
}
|
||||
|
||||
int picWidth(short nPic, short repeat) {
|
||||
return ClipLow((tilesiz[nPic].y * repeat) >> 2, 0);
|
||||
}
|
||||
|
||||
int picHeight(short nPic, short repeat) {
|
||||
return ClipLow((tilesiz[nPic].y * repeat) << 2, 0);
|
||||
}
|
||||
|
||||
END_BLD_NS
|
||||
|
|
|
@ -83,5 +83,7 @@ int GetDistToLine(int x1, int y1, int x2, int y2, int x3, int y3);
|
|||
unsigned int ClipMove(int *x, int *y, int *z, int *nSector, int xv, int yv, int wd, int cd, int fd, unsigned int nMask);
|
||||
int GetClosestSectors(int nSector, int x, int y, int nDist, short *pSectors, char *pSectBit);
|
||||
int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, short *pSectors, char *pSectBit, short *a8);
|
||||
int picWidth(short nPic, short repeat);
|
||||
int picHeight(short nPic, short repeat);
|
||||
|
||||
END_BLD_NS
|
||||
|
|
|
@ -1113,6 +1113,18 @@ void playerStart(int nPlayer)
|
|||
pPlayer->posture = 1;
|
||||
pPlayer->pXSprite->medium = kMediumWater;
|
||||
}
|
||||
|
||||
/////////////////
|
||||
// reset qav scene
|
||||
playerResetQavScene(pPlayer);
|
||||
|
||||
// restore default movement speed
|
||||
playerResetMoveSpeed(pPlayer);
|
||||
|
||||
// restore default jump height
|
||||
playerResetJumpHeight(pPlayer);
|
||||
/////////////////
|
||||
|
||||
}
|
||||
|
||||
void playerReset(PLAYER *pPlayer)
|
||||
|
@ -1160,9 +1172,7 @@ void playerReset(PLAYER *pPlayer)
|
|||
|
||||
/////////////////
|
||||
// reset qav scene
|
||||
QAVSCENE* pQavScene = &gPlayerCtrl[pPlayer->nPlayer].qavScene;
|
||||
pQavScene->index = pQavScene->causedBy = pPlayer->sceneQav = -1;
|
||||
pQavScene->qavResrc = NULL;
|
||||
playerResetQavScene(pPlayer);
|
||||
|
||||
// restore default movement speed
|
||||
playerResetMoveSpeed(pPlayer);
|
||||
|
@ -1188,6 +1198,12 @@ void playerResetJumpHeight(PLAYER* pPlayer) {
|
|||
}
|
||||
}
|
||||
|
||||
void playerResetQavScene(PLAYER* pPlayer) {
|
||||
QAVSCENE* pQavScene = &gPlayerCtrl[pPlayer->nPlayer].qavScene;
|
||||
pQavScene->index = pQavScene->causedBy = pPlayer->sceneQav = -1;
|
||||
pQavScene->qavResrc = NULL;
|
||||
}
|
||||
|
||||
int dword_21EFB0[8];
|
||||
ClockTicks dword_21EFD0[8];
|
||||
|
||||
|
|
|
@ -332,5 +332,6 @@ void qavScenePlay(PLAYER* pPlayer);
|
|||
void qavSceneDraw(PLAYER* pPlayer, int a2, int a3, int a4, int a5);
|
||||
void playerResetMoveSpeed(PLAYER* pPlayer);
|
||||
void playerResetJumpHeight(PLAYER* pPlayer);
|
||||
void playerResetQavScene(PLAYER* pPlayer);
|
||||
|
||||
END_BLD_NS
|
||||
|
|
|
@ -104,8 +104,9 @@ void scrLoadPLUs(void)
|
|||
parallaxvisibility = 3072;
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < 15; i++)
|
||||
{
|
||||
|
||||
// load default palookups
|
||||
for (int i = 0; i < 15; i++) {
|
||||
DICTNODE *pPlu = gSysRes.Lookup(PLU[i].name, "PLU");
|
||||
if (!pPlu)
|
||||
ThrowError("%s.PLU not found", PLU[i].name);
|
||||
|
@ -113,6 +114,15 @@ void scrLoadPLUs(void)
|
|||
ThrowError("Incorrect PLU size");
|
||||
palookup[PLU[i].id] = (char*)gSysRes.Lock(pPlu);
|
||||
}
|
||||
|
||||
// by NoOne: load user palookups
|
||||
for (int i = kUserPLUStart; i < MAXPALOOKUPS; i++) {
|
||||
DICTNODE* pPlu = gSysRes.Lookup(i, "PLU");
|
||||
if (!pPlu) continue;
|
||||
else if (pPlu->size / 256 != 64) { consoleSysMsg("Incorrect filesize of PLU#%d", i); }
|
||||
else palookup[i] = (char*)gSysRes.Lock(pPlu);
|
||||
}
|
||||
|
||||
#ifdef USE_OPENGL
|
||||
palookupfog[1].r = 255;
|
||||
palookupfog[1].g = 255;
|
||||
|
|
|
@ -388,10 +388,8 @@ void seqSpawn(int a1, int a2, int a3, int a4)
|
|||
if (!pInst) return;
|
||||
|
||||
DICTNODE *hSeq = gSysRes.Lookup(a1, "SEQ");
|
||||
if (!hSeq) {
|
||||
viewSetSystemMessage("Missing sequence #%d", a1);
|
||||
return;
|
||||
}
|
||||
if (!hSeq)
|
||||
ThrowError("Missing sequence #%d", a1);
|
||||
|
||||
int i = activeCount;
|
||||
if (pInst->at13)
|
||||
|
@ -588,7 +586,7 @@ void SeqLoadSave::Load(void)
|
|||
int nSeq = pInst->at8;
|
||||
DICTNODE *hSeq = gSysRes.Lookup(nSeq, "SEQ");
|
||||
if (!hSeq) {
|
||||
viewSetSystemMessage("Missing sequence #%d", nSeq);
|
||||
ThrowError("Missing sequence #%d", nSeq);
|
||||
continue;
|
||||
}
|
||||
Seq *pSeq = (Seq*)gSysRes.Lock(hSeq);
|
||||
|
|
|
@ -69,6 +69,18 @@ int nUniMissileTrapClient = seqRegisterClient(UniMissileTrapSeqCallback);
|
|||
int nMGunFireClient = seqRegisterClient(MGunFireSeqCallback);
|
||||
int nMGunOpenClient = seqRegisterClient(MGunOpenSeqCallback);
|
||||
|
||||
int gRdata[4];
|
||||
int* xspriData2Array(int nXSprite) {
|
||||
if (xspriRangeIsFine(nXSprite)) {
|
||||
gRdata[0] = xsprite[nXSprite].data1; gRdata[2] = xsprite[nXSprite].data3;
|
||||
gRdata[1] = xsprite[nXSprite].data2; gRdata[3] = xsprite[nXSprite].data4;
|
||||
return gRdata;
|
||||
}
|
||||
|
||||
memset(gRdata, 0, sizeof(gRdata));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int GetWaveValue(unsigned int nPhase, int nType)
|
||||
{
|
||||
switch (nType)
|
||||
|
@ -368,9 +380,6 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
|
|||
{
|
||||
spritetype *pSprite = &sprite[nSprite];
|
||||
|
||||
//if (pSprite->type != 706 && pSprite->type != 707)
|
||||
//viewSetSystemMessage("SPRITE %d (TYPE %d), EVENT INITED BY: %d", nSprite, pSprite->type, event.causedBy);
|
||||
|
||||
if (gModernMap) {
|
||||
switch (event.cmd) {
|
||||
case kCmdUnlock:
|
||||
|
@ -441,39 +450,37 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
|
|||
|
||||
// Random Event Switch takes random data field and uses it as TX ID
|
||||
case kModernRandomTX: {
|
||||
std::default_random_engine rng; int tx = 0; int maxRetries = 10;
|
||||
int tx = 0; int maxRetries = 10;
|
||||
// set range of TX ID if data2 and data3 is empty.
|
||||
if (pXSprite->data1 > 0 && pXSprite->data2 <= 0 && pXSprite->data3 <= 0 && pXSprite->data4 > 0) {
|
||||
|
||||
// data1 must be less than data4
|
||||
if (pXSprite->data1 > pXSprite->data4) {
|
||||
short tmp = pXSprite->data1;
|
||||
pXSprite->data1 = (short)pXSprite->data4;
|
||||
pXSprite->data1 = pXSprite->data4;
|
||||
pXSprite->data4 = tmp;
|
||||
}
|
||||
|
||||
int total = pXSprite->data4 - pXSprite->data1;
|
||||
while (maxRetries > 0) {
|
||||
|
||||
// use true random only for single player mode
|
||||
// otherwise use Blood's default one. In the future it maybe possible to make
|
||||
// host send info to clients about what was generated.
|
||||
|
||||
if (gGameOptions.nGameType != 0 || VanillaMode() || DemoRecordStatus()) tx = Random(total) + pXSprite->data1;
|
||||
else {
|
||||
rng.seed(std::random_device()());
|
||||
tx = (int)my_random(pXSprite->data1, pXSprite->data4);
|
||||
}
|
||||
|
||||
// use true random only for single player mode, otherwise use Blood's default one.
|
||||
if (gGameOptions.nGameType == 0 && !VanillaMode() && !DemoRecordStatus()) tx = STD_Random(pXSprite->data1, pXSprite->data4);
|
||||
else tx = Random(total) + pXSprite->data1;
|
||||
|
||||
if (tx != pXSprite->txID) break;
|
||||
maxRetries--;
|
||||
}
|
||||
|
||||
} else {
|
||||
while (maxRetries > 0) {
|
||||
if ((tx = GetRandDataVal(NULL, pSprite)) > 0 && tx != pXSprite->txID) break;
|
||||
maxRetries--;
|
||||
|
||||
int* rData = xspriData2Array(pSprite->extra);
|
||||
if (rData != NULL) {
|
||||
while (maxRetries > 0) {
|
||||
if ((tx = GetRandDataVal(rData)) > 0 && tx != pXSprite->txID) break;
|
||||
maxRetries--;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (tx > 0) {
|
||||
|
@ -628,7 +635,6 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
|
|||
case kModernObjPicnumChanger:
|
||||
case kModernSectorFXChanger:
|
||||
case kModernObjDataChanger:
|
||||
case kModernConcussSprite:
|
||||
modernTypeSetSpriteState(nSprite, pXSprite, pXSprite->state ^ 1, event.causedBy);
|
||||
return;
|
||||
|
||||
|
@ -871,7 +877,7 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
|
|||
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 = &gPlayerCtrl[pPlayer->nPlayer];
|
||||
if (event.cmd >= kCmdNumberic) {
|
||||
switch (event.cmd) {
|
||||
case kCmdNumberic + 3:// start playing qav scene
|
||||
|
@ -1017,44 +1023,48 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
|
|||
switch (pXSprite->data2) {
|
||||
// erase all
|
||||
case 0:
|
||||
fallthrough__;
|
||||
|
||||
// erase weapons
|
||||
case 1:
|
||||
// erase all
|
||||
if (pXSprite->data3 <= 0) {
|
||||
WeaponLower(pPlayer);
|
||||
|
||||
for (int i = 0; i < 14; i++) {
|
||||
pPlayer->hasWeapon[i] = false;
|
||||
// also erase ammo
|
||||
if (i < 12) pPlayer->ammoCount[i] = 0;
|
||||
}
|
||||
|
||||
pPlayer->hasWeapon[1] = true;
|
||||
pPlayer->curWeapon = 0;
|
||||
pPlayer->nextWeapon = 1;
|
||||
|
||||
WeaponRaise(pPlayer);
|
||||
|
||||
// erase just specified
|
||||
} else {
|
||||
WeaponLower(pPlayer);
|
||||
|
||||
for (int i = 0; i < 14; i++) {
|
||||
pPlayer->hasWeapon[i] = false;
|
||||
// also erase ammo
|
||||
if (i < 12) pPlayer->ammoCount[i] = 0;
|
||||
}
|
||||
|
||||
pPlayer->hasWeapon[1] = true;
|
||||
pPlayer->curWeapon = 0;
|
||||
pPlayer->nextWeapon = 1;
|
||||
|
||||
WeaponRaise(pPlayer);
|
||||
if (pXSprite->data2) break;
|
||||
fallthrough__;
|
||||
|
||||
// erase all armor
|
||||
case 2:
|
||||
for (int i = 0; i < 3; i++) pPlayer->armor[i] = 0;
|
||||
if (pXSprite->data2) break;
|
||||
fallthrough__;
|
||||
|
||||
// erase all pack items
|
||||
case 3:
|
||||
for (int i = 0; i < 5; i++) {
|
||||
pPlayer->packSlots[i].isActive = pPlayer->packSlots[i].curAmount = 0;
|
||||
pPlayer->packSlots[i].isActive = false;
|
||||
pPlayer->packSlots[i].curAmount = 0;
|
||||
pPlayer->packItemId = -1;
|
||||
}
|
||||
if (pXSprite->data2) break;
|
||||
fallthrough__;
|
||||
|
||||
// erase all keys
|
||||
case 4:
|
||||
for (int i = 0; i < 8; i++) pPlayer->hasKey[i] = false;
|
||||
if (pXSprite->data2) break;
|
||||
fallthrough__;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1094,11 +1104,14 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
|
|||
case kCmdNumberic + 8: // 72
|
||||
// use inventory item
|
||||
if (pXSprite->data2 > 0 && pXSprite->data2 <= 5) {
|
||||
packUseItem(pPlayer, pXSprite->data2 - 1);
|
||||
unsigned int invItem = pXSprite->data2 - 1;
|
||||
packUseItem(pPlayer, invItem);
|
||||
|
||||
// force remove after use
|
||||
if (pXSprite->data4 == 1)
|
||||
pPlayer->packSlots[0].curAmount = pPlayer->packSlots[0].curAmount = 0;
|
||||
if (pXSprite->data4 == 1) {
|
||||
pPlayer->packSlots[invItem].isActive = false;
|
||||
pPlayer->packSlots[invItem].curAmount = 0;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
@ -1290,8 +1303,12 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
|
|||
pXSpawn->target = -1;
|
||||
aiActivateDude(pSpawn, pXSpawn);
|
||||
break;
|
||||
default:
|
||||
if (gModernMap && (pSprite->flags & kModernTypeFlag3)) aiActivateDude(pSpawn, pXSpawn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1350,6 +1367,7 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
|
|||
sfxPlay3DSound(pSprite, 452, 0, 0);
|
||||
evPost(nSprite, 3, 30, kCmdOff, event.causedBy);
|
||||
pXSprite->state = 1;
|
||||
fallthrough__;
|
||||
case kCmdOn:
|
||||
sfxPlay3DSound(pSprite, 451, 0, 0);
|
||||
pXSprite->Proximity = 1;
|
||||
|
@ -1451,19 +1469,6 @@ void stopWindOnSectors(XSPRITE* pXSource) {
|
|||
pXSector->windVel = 0;
|
||||
}
|
||||
}
|
||||
/// WIP ////////////////////////////////////////////////////////
|
||||
void useConcussSprite(XSPRITE* pXSource, spritetype* pSprite) {
|
||||
spritetype* pSource = &sprite[pXSource->reference];
|
||||
int nIndex = isDebris(pSprite->index);
|
||||
//ThrowError("%d", gPhysSpritesList[nIndex]);
|
||||
//int size = (tilesiz[pSprite->picnum].x * pSprite->xrepeat * tilesiz[pSprite->picnum].y * pSprite->yrepeat) >> 1;
|
||||
//int t = scale(pXSource->data1, size, gSpriteMass[pSprite->extra].mass);
|
||||
//xvel[pSprite->xvel] += mulscale16(t, pSprite->x);
|
||||
//yvel[pSprite->xvel] += mulscale16(t, pSprite->y);
|
||||
//zvel[pSprite->xvel] += mulscale16(t, pSprite->z);
|
||||
|
||||
//debrisConcuss(pXSource->reference, nIndex, pSprite->x - 100, pSprite->y - 100, pSprite->z - 100, pXSource->data1);
|
||||
}
|
||||
|
||||
void trPlayerCtrlStartScene(XSPRITE* pXSource, PLAYER* pPlayer, int causedBy) {
|
||||
|
||||
|
@ -1501,7 +1506,7 @@ void trPlayerCtrlStartScene(XSPRITE* pXSource, PLAYER* pPlayer, int causedBy) {
|
|||
void trPlayerCtrlStopScene(XSPRITE* pXSource, PLAYER* pPlayer) {
|
||||
|
||||
TRPLAYERCTRL* pCtrl = &gPlayerCtrl[pPlayer->nPlayer];
|
||||
viewSetSystemMessage("OFF %d", pCtrl->qavScene.index);
|
||||
//viewSetSystemMessage("OFF %d", pCtrl->qavScene.index);
|
||||
|
||||
pXSource->sysData1 = 0;
|
||||
pCtrl->qavScene.index = -1;
|
||||
|
@ -2029,22 +2034,29 @@ void useSectorWindGen(XSPRITE* pXSource, sectortype* pSector) {
|
|||
|
||||
|
||||
void useSpriteDamager(XSPRITE* pXSource, spritetype* pSprite) {
|
||||
|
||||
spritetype* pSource = &sprite[pXSource->reference];
|
||||
if (pSprite != NULL && xspriIsFine(pSprite->index)) {
|
||||
int dmg = (pXSource->data3 == 0) ? 65535 : ClipRange(pXSource->data3, 1, 65535);
|
||||
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);
|
||||
if (pSprite != NULL && xspriRangeIsFine(pSprite->extra)) {
|
||||
XSPRITE* pXSprite = &xsprite[pSprite->extra];
|
||||
DAMAGE_TYPE dmgType = (DAMAGE_TYPE) ClipRange(pXSource->data2, kDmgFall, kDmgElectric);
|
||||
int dmg = (pXSource->data3 == 0) ? 65535 : ClipRange(pXSource->data3 << 1, 1, 65535);
|
||||
if (pXSprite->data2 >= 0) actDamageSprite(pSource->index, pSprite, dmgType, dmg);
|
||||
else if (pXSource->data2 == -1 && IsDudeSprite(pSprite)) {
|
||||
PLAYER* pPlayer = getPlayerById(pSprite->type);
|
||||
if (pPlayer == NULL || !pPlayer->godMode) {
|
||||
xsprite[pSprite->extra].health = ClipLow(xsprite[pSprite->extra].health - dmg, 0);
|
||||
if (xsprite[pSprite->extra].health == 0)
|
||||
actKillDude(pSource->index, pSprite, dmgType, 65535);
|
||||
}
|
||||
}
|
||||
else actDamageSprite(pSource->index, pSprite, (DAMAGE_TYPE)dmgType, dmg);
|
||||
}
|
||||
}
|
||||
|
||||
void useSeqSpawnerGen(XSPRITE* pXSource, int objType, int index) {
|
||||
if (pXSource->data2 > 0 && !gSysRes.Lookup(pXSource->data2, "SEQ")) {
|
||||
consoleSysMsg("Missing sequence #%d",pXSource->data2);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (objType) {
|
||||
case 6:
|
||||
if (pXSource->data2 <= 0) {
|
||||
|
@ -2089,7 +2101,7 @@ void useSeqSpawnerGen(XSPRITE* pXSource, int objType, int index) {
|
|||
|
||||
if (pXSource->data4 > 0) {
|
||||
|
||||
int cx, cy, cz, wx, wy, wz;
|
||||
int cx, cy, cz;
|
||||
cx = (wall[index].x + wall[wall[index].point2].x) >> 1;
|
||||
cy = (wall[index].y + wall[wall[index].point2].y) >> 1;
|
||||
int nSector = sectorofwall(index);
|
||||
|
@ -2099,9 +2111,6 @@ void useSeqSpawnerGen(XSPRITE* pXSource, int objType, int index) {
|
|||
getzsofslope(wall[index].nextsector, cx, cy, &ceilZ2, &floorZ2);
|
||||
ceilZ = ClipLow(ceilZ, ceilZ2);
|
||||
floorZ = ClipHigh(floorZ, floorZ2);
|
||||
wz = floorZ - ceilZ;
|
||||
wx = wall[wall[index].point2].x - wall[index].x;
|
||||
wy = wall[wall[index].point2].y - wall[index].y;
|
||||
cz = (ceilZ + floorZ) >> 1;
|
||||
|
||||
sfxPlay3DSound(cx, cy, cz, pXSource->data4, nSector);
|
||||
|
@ -3476,14 +3485,7 @@ void pastePropertiesInObj(int type, int nDest, EVENT event) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (pSource->type == kModernConcussSprite) {
|
||||
/* - Concussing any physics affected sprite with give strength - */
|
||||
if (type != 3) return;
|
||||
else if ((sprite[nDest].flags & kPhysMove) || (sprite[nDest].flags & kPhysGravity) || isDebris(nDest))
|
||||
useConcussSprite(pXSource, &sprite[nDest]);
|
||||
return;
|
||||
|
||||
} else if (pSource->type == kMarkerWarpDest) {
|
||||
if (pSource->type == kMarkerWarpDest) {
|
||||
/* - Allows teleport any sprite from any location to the source destination - */
|
||||
useTeleportTarget(pXSource, &sprite[nDest]);
|
||||
return;
|
||||
|
@ -3503,7 +3505,6 @@ void pastePropertiesInObj(int type, int nDest, EVENT event) {
|
|||
}
|
||||
else if (pSource->type == kModernSeqSpawner) {
|
||||
/* - SEQ Spawner takes data2 as SEQ ID and spawns it on it's or TX ID sprite - */
|
||||
if (pXSource->data2 > 0 && !gSysRes.Lookup(pXSource->data2, "SEQ")) return;
|
||||
useSeqSpawnerGen(pXSource, type, nDest);
|
||||
return;
|
||||
}
|
||||
|
@ -3635,7 +3636,7 @@ void pastePropertiesInObj(int type, int nDest, EVENT event) {
|
|||
if ((pSource->flags & kModernTypeFlag1) || (pXSource->data3 != -1 && pXSource->data3 != 32767))
|
||||
setDataValueOfObject(type, nDest, 3, pXSource->data3, event.causedBy);
|
||||
|
||||
if ((pSource->flags & kModernTypeFlag1) || (pXSource->data4 != -1 && pXSource->data1 != 65535))
|
||||
if ((pSource->flags & kModernTypeFlag1) || pXSource->data4 != 65535)
|
||||
setDataValueOfObject(type, nDest, 4, pXSource->data4, event.causedBy);
|
||||
break;
|
||||
|
||||
|
@ -4838,7 +4839,7 @@ void ActivateGenerator(int nSprite)
|
|||
if (pXSprite->dropMsg > 0) {
|
||||
for (short nItem = headspritestat[kStatItem]; nItem >= 0; nItem = nextspritestat[nItem]) {
|
||||
spritetype* pItem = &sprite[nItem];
|
||||
if (pItem->type == pXSprite->dropMsg && pItem->x == pSprite->x && pItem->y == pSprite->y && pItem->z == pSprite->z) {
|
||||
if ((unsigned int)pItem->type == pXSprite->dropMsg && pItem->x == pSprite->x && pItem->y == pSprite->y && pItem->z == pSprite->z) {
|
||||
gFX.fxSpawn((FX_ID)29, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0);
|
||||
deletesprite(nItem);
|
||||
break;
|
||||
|
|
|
@ -86,6 +86,9 @@ bool valueIsBetween(int val, int min, int max);
|
|||
void trPlayerCtrlLink(XSPRITE* pXSource, PLAYER* pPlayer);
|
||||
void trPlayerCtrlStartScene(XSPRITE* pXSource, PLAYER* pPlayer, int causedBy);
|
||||
void trPlayerCtrlStopScene(XSPRITE* pXSource, PLAYER* pPlayer);
|
||||
|
||||
extern int gRdata[4];
|
||||
int* xspriData2Array(int nXSprite);
|
||||
// -------------------------------------------------------
|
||||
|
||||
END_BLD_NS
|
||||
|
|
Loading…
Reference in a new issue