- Event redirection support for modern types

- New modern type "Condition" (WIP)
- Fix damage scale for custom dude
- Extend Impact and Vector flags so they can be used with dudes
- Impact condition can be triggered with missiles and explosions
- Updates for Teleport Target type (gModernMap)
- Updates for Effect Gen type
- Updates for Wind Gen type

# Conflicts:
#	source/blood/src/actor.cpp
#	source/blood/src/aiunicult.h
This commit is contained in:
NoOneBlood 2020-03-01 23:36:28 +03:00 committed by Christoph Oelckers
parent 8eef69b1a6
commit bdca9420f5
8 changed files with 915 additions and 494 deletions

View file

@ -2461,11 +2461,13 @@ const int DudeDifficulty[5] = {
void actInit(bool bSaveLoad) {
#ifdef NOONE_EXTENSIONS
if (!gModernMap) initprintf("> This map *does not* provides modern features.\n");
else {
initprintf("> This map provides modern features.\n");
if (!gModernMap) {
//initprintf("> This map *does not* provides modern features.\n");
nnExtResetGlobals();
} else {
//initprintf("> This map provides modern features.\n");
nnExtInitModernStuff(bSaveLoad);
}
}
#endif
for (int nSprite = headspritestat[kStatItem]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
@ -3979,6 +3981,11 @@ void actImpactMissile(spritetype *pMissile, int hitCode)
}
break;
}
#ifdef NOONE_EXTENSIONS
if (gModernMap && pXSpriteHit && pXSpriteHit->state != pXSpriteHit->restState && pXSpriteHit->Impact)
trTriggerSprite(nSpriteHit, pXSpriteHit, kCmdSpriteImpact);
#endif
pMissile->cstat &= ~257;
}
@ -5768,21 +5775,6 @@ void actProcessSprites(void)
}
}
#ifdef NOONE_EXTENSIONS
// add impulse for sprites from physics list
if (gPhysSpritesCount > 0 && pExplodeInfo->dmgType != 0 && pXSprite->data1 != 0) {
for (int i = 0; i < gPhysSpritesCount; i++) {
if (gPhysSpritesList[i] == -1) continue;
else if (sprite[gPhysSpritesList[i]].sectnum < 0 || (sprite[gPhysSpritesList[i]].flags & kHitagFree) != 0)
continue;
spritetype* pDebris = &sprite[gPhysSpritesList[i]];
if (!TestBitString(v24c, pDebris->sectnum) || !CheckProximity(pDebris, x, y, z, nSector, radius)) continue;
else debrisConcuss(nOwner, i, x, y, z, pExplodeInfo->dmgType);
}
}
#endif
for (int p = connecthead; p >= 0; p = connectpoint2[p])
{
spritetype *pSprite2 = gPlayer[p].pSprite;
@ -5793,7 +5785,40 @@ void actProcessSprites(void)
int t = divscale16(pXSprite->data2, nDist);
gPlayer[p].flickerEffect += t;
}
#ifdef NOONE_EXTENSIONS
if (pXSprite->data1 != 0) {
// add impulse for sprites from physics list
if (gPhysSpritesCount > 0 && pExplodeInfo->dmgType != 0) {
for (int i = 0; i < gPhysSpritesCount; i++) {
if (gPhysSpritesList[i] == -1) continue;
else if (sprite[gPhysSpritesList[i]].sectnum < 0 || (sprite[gPhysSpritesList[i]].flags & kHitagFree) != 0)
continue;
spritetype* pDebris = &sprite[gPhysSpritesList[i]];
if (!TestBitString(v24c, pDebris->sectnum) || !CheckProximity(pDebris, x, y, z, nSector, radius)) continue;
else debrisConcuss(nOwner, i, x, y, z, pExplodeInfo->dmgType);
}
}
// trigger sprites from impact list
if (gImpactSpritesCount > 0) {
for (int i = 0; i < gImpactSpritesCount; i++) {
if (gImpactSpritesList[i] == -1) continue;
else if (sprite[gImpactSpritesList[i]].sectnum < 0 || (sprite[gImpactSpritesList[i]].flags & kHitagFree) != 0)
continue;
spritetype* pImpact = &sprite[gImpactSpritesList[i]]; XSPRITE* pXImpact = &xsprite[pImpact->extra];
if (/*pXImpact->state == pXImpact->restState ||*/ !TestBitString(v24c, pImpact->sectnum) || !CheckProximity(pImpact, x, y, z, nSector, radius))
continue;
trTriggerSprite(pImpact->index, pXImpact, kCmdSpriteImpact);
}
}
}
if (!gModernMap || !(pSprite->flags & kModernTypeFlag1)) {
// if data4 > 0, do not remove explosion. This can be useful when designer wants put explosion generator in map manually
// via sprite statnum 2.

View file

@ -179,9 +179,9 @@ GENDUDEEXTRA* genDudeExtra(spritetype* pGenDude) {
}
void genDudeUpdate(spritetype* pSprite) {
GENDUDEEXTRA* pExtra = genDudeExtra(pSprite);
for (int i = 0; i < kGenDudePropertyMax; i++) {
if (gGenDudeExtra[pSprite->index].updReq[i])
genDudePrepare(pSprite, i);
if (pExtra->updReq[i]) genDudePrepare(pSprite, i);
}
}
@ -1273,83 +1273,82 @@ void scaleDamage(XSPRITE* pXSprite) {
short curWeapon = gGenDudeExtra[sprite[pXSprite->reference].index].curWeapon;
short weaponType = gGenDudeExtra[sprite[pXSprite->reference].index].weaponType;
unsigned short* curScale = gGenDudeExtra[sprite[pXSprite->reference].index].dmgControl;
signed short* curScale = gGenDudeExtra[sprite[pXSprite->reference].index].dmgControl;
for (int i = 0; i < kDmgMax; i++)
curScale[i] = getDudeInfo(kDudeModernCustom)->startDamage[i];
// all enemies with vector weapons gets extra resistance to bullet damage
if (weaponType == kGenDudeWeaponHitscan) {
curScale[kDmgBullet] -= 10;
// just copy damage resistance of dude that should be summoned
} else if (weaponType == kGenDudeWeaponSummon) {
for (int i = 0; i < kDmgMax; i++)
curScale[i] = getDudeInfo(curWeapon)->startDamage[i];
// these does not like the explosions and burning
} else if (weaponType == kGenDudeWeaponKamikaze) {
curScale[kDmgBurn] = curScale[kDmgExplode] = 512;
} else if (weaponType == kGenDudeWeaponMissile || weaponType == kGenDudeWeaponThrow) {
switch (curWeapon) {
case kMissileButcherKnife:
curScale[kDmgBullet] = 100;
fallthrough__;
case kMissileEctoSkull:
curScale[kDmgSpirit] = 32;
break;
case kMissileLifeLeechAltNormal:
case kMissileLifeLeechAltSmall:
case kMissileArcGargoyle:
curScale[kDmgSpirit] = 32;
curScale[kDmgElectric] = 52;
break;
case kMissileFlareRegular:
case kMissileFlareAlt:
case kMissileFlameSpray:
case kMissileFlameHound:
case kThingArmedSpray:
case kThingPodFireBall:
case kThingNapalmBall:
curScale[kDmgBurn] = 32;
curScale[kDmgExplode] -= 20;
break;
case kMissileLifeLeechRegular:
case kThingDroppedLifeLeech:
case kModernThingEnemyLifeLeech:
curScale[kDmgSpirit] = 32 + Random(18);
curScale[kDmgBurn] = 60 + Random(4);
for (int i = 2; i < kDmgMax; i++) {
if (Chance(0x1000) && i != kDmgSpirit)
curScale[i] = 48 + Random(32);
}
break;
case kMissileFireball:
case kMissileFireballNapam:
case kMissileFireballCerberus:
case kMissileFireballTchernobog:
curScale[kDmgBurn] = 50;
curScale[kDmgExplode] = 32;
curScale[kDmgFall] = 65 + Random(15);
break;
case kThingTNTBarrel:
case kThingArmedProxBomb:
case kThingArmedRemoteBomb:
case kThingArmedTNTBundle:
case kThingArmedTNTStick:
case kModernThingTNTProx:
curScale[kDmgExplode] = 32;
curScale[kDmgFall] = 65 + Random(15);
break;
case kMissileTeslaAlt:
case kMissileTeslaRegular:
curScale[kDmgElectric] = 32 + Random(8);
break;
}
switch (weaponType) {
// all enemies with vector weapons gets extra resistance to bullet damage
case kGenDudeWeaponHitscan:
curScale[kDmgBullet] -= 10;
break;
// just copy damage resistance of dude that should be summoned
case kGenDudeWeaponSummon:
for (int i = 0; i < kDmgMax; i++)
curScale[i] = getDudeInfo(curWeapon)->startDamage[i];
break;
// these does not like the explosions and burning
case kGenDudeWeaponKamikaze:
curScale[kDmgBurn] = curScale[kDmgExplode] = curScale[kDmgElectric] = 1024;
break;
case kGenDudeWeaponMissile:
case kGenDudeWeaponThrow:
switch (curWeapon) {
case kMissileButcherKnife:
curScale[kDmgBullet] = 100;
fallthrough__;
case kMissileEctoSkull:
curScale[kDmgSpirit] = 32;
break;
case kMissileLifeLeechAltNormal:
case kMissileLifeLeechAltSmall:
case kMissileArcGargoyle:
curScale[kDmgSpirit] = 32;
curScale[kDmgElectric] = 52;
break;
case kMissileFlareRegular:
case kMissileFlareAlt:
case kMissileFlameSpray:
case kMissileFlameHound:
case kThingArmedSpray:
case kThingPodFireBall:
case kThingNapalmBall:
curScale[kDmgBurn] = 32;
curScale[kDmgExplode] -= 20;
break;
case kMissileLifeLeechRegular:
case kThingDroppedLifeLeech:
case kModernThingEnemyLifeLeech:
curScale[kDmgSpirit] = 32 + Random(18);
curScale[kDmgBurn] = 60 + Random(4);
for (int i = 2; i < kDmgMax; i++) {
if (Chance(0x1000) && i != kDmgSpirit)
curScale[i] = 48 + Random(32);
}
break;
case kMissileFireball:
case kMissileFireballNapam:
case kMissileFireballCerberus:
case kMissileFireballTchernobog:
curScale[kDmgBurn] = 50;
curScale[kDmgExplode] = 32;
curScale[kDmgFall] = 65 + Random(15);
break;
case kThingTNTBarrel:
case kThingArmedProxBomb:
case kThingArmedRemoteBomb:
case kThingArmedTNTBundle:
case kThingArmedTNTStick:
case kModernThingTNTProx:
curScale[kDmgExplode] = 32;
curScale[kDmgFall] = 65 + Random(15);
break;
case kMissileTeslaAlt:
case kMissileTeslaRegular:
curScale[kDmgElectric] = 32 + Random(8);
break;
}
break;
}
@ -1395,7 +1394,6 @@ void scaleDamage(XSPRITE* pXSprite) {
// take surface type into account
int surfType = tileGetSurfType(sprite[pXSprite->reference].index + 0xc000);
//int surfType = 4;
switch (surfType) {
case 1: // stone
curScale[kDmgFall] = 0;
@ -1944,11 +1942,11 @@ int genDudeSeqStartId(XSPRITE* pXSprite) {
}
bool genDudePrepare(spritetype* pSprite, int propId) {
if (!(pSprite->index >= 0 && pSprite->index < kMaxSprites)) {
consoleSysMsg("pSprite->index >= 0 && pSprite->index < kMaxSprites");
if (!spriRangeIsFine(pSprite->index)) {
consoleSysMsg("!spriRangeIsFine(pSprite->index)");
return false;
} else if (!(pSprite->extra >= 0 && pSprite->extra < kMaxXSprites)) {
consoleSysMsg("pSprite->extra >= 0 && pSprite->extra < kMaxXSprites");
} else if (!xspriRangeIsFine(pSprite->extra)) {
consoleSysMsg("!xspriRangeIsFine(pSprite->extra)");
return false;
} else if (pSprite->type != kDudeModernCustom) {
consoleSysMsg("pSprite->type != kDudeModernCustom");
@ -1974,8 +1972,8 @@ bool genDudePrepare(spritetype* pSprite, int propId) {
case kGenDudePropertyWeapon: {
pExtra->curWeapon = pXSprite->data1;
switch (pXSprite->data1) {
case 19: pExtra->curWeapon = 2; break;
case 310: pExtra->curWeapon = kMissileArcGargoyle; break;
case VECTOR_TYPE_19: pExtra->curWeapon = VECTOR_TYPE_2; break;
case kMissileUnused: pExtra->curWeapon = kMissileArcGargoyle; break;
case kThingDroppedLifeLeech: pExtra->curWeapon = kModernThingEnemyLifeLeech; break;
}

View file

@ -156,7 +156,6 @@ extern const GENDUDESND gCustomDudeSnd[];
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
@ -166,6 +165,7 @@ struct GENDUDEEXTRA {
unsigned short slaveCount; // how many dudes is summoned
signed short nLifeLeech; // spritenum of dropped dude's leech
signed short slave[kGenDudeMaxSlaves]; // index of the ones dude is summon
signed short dmgControl[kDamageMax]; // depends of current weapon, drop armor item, sprite yrepeat and surface type
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

View file

@ -327,6 +327,7 @@ enum {
kMissileEctoSkull = 307,
kMissileFlameHound = 308,
kMissilePukeGreen = 309,
kMissileUnused = 310,
kMissileArcGargoyle = 311,
kMissileFireballNapam = 312,
kMissileFireballCerberus = 313,

View file

@ -124,6 +124,10 @@ inline bool playerRXRngIsFine(int rx) {
return (rx >= kChannelPlayer0 && rx < kChannelPlayer7);
}
inline bool channelRangeIsFine(int channel) {
return (channel >= kChannelUser && channel < kChannelUserMax);
}
struct EVENT {
unsigned int index: 14; // index
unsigned int type: 3; // type

File diff suppressed because it is too large Load diff

View file

@ -52,16 +52,23 @@ BEGIN_BLD_NS
#define kPhysDebrisExplode 0x0800 // *debris* can be affected by explosions
// *modern types only hitag*
#define kModernTypeFlag0 0x0
#define kModernTypeFlag1 0x1
#define kModernTypeFlag2 0x2
#define kModernTypeFlag3 0x3
#define kModernTypeFlag0 0x0000
#define kModernTypeFlag1 0x0001
#define kModernTypeFlag2 0x0002
#define kModernTypeFlag3 0x0003
#define kModernTypeFlag4 0x0004
#define kMaxRandomizeRetries 16
// modern sprite types
// modern statnums
enum {
kStatModernDudeTargetChanger = 20,
kStatModernCondition = 21,
kStatModernEventRedirector = 22,
};
// modern sprite types
enum {
kModernCustomDudeSpawn = 24,
kModernRandomTX = 25,
kModernSequentialTX = 26,
@ -87,6 +94,7 @@ kModernThingTNTProx = 433, // detects only players
kModernThingThrowableRock = 434, // does small damage if hits target
kModernThingEnemyLifeLeech = 435, // the same as normal, except it aims in specified target only
kModernPlayerControl = 500, /// WIP
kModernCondition = 501, /// WIP, sends command only if specified conditions == true
kGenModernMissileUniversal = 704,
kGenModernSound = 708,
};
@ -105,7 +113,6 @@ OBJ_SPRITE = 3,
OBJ_SECTOR = 6,
};
// - STRUCTS ------------------------------------------------------------------
struct SPRITEMASS { // sprite mass info for getSpriteMassBySize();
int seqId;
@ -135,6 +142,13 @@ struct VECTORINFO_EXTRA {
struct MISSILEINFO_EXTRA {
int fireSound[2]; // predefined fire sounds. used by kDudeModernCustom, but can be used for something else.
bool dmgType[kDamageMax]; // list of damages types missile can use
bool allowImpact; // allow to trigger object with Impact flag enabled with this missile
};
struct DUDEINFO_EXTRA {
bool flying; // used by kModernDudeTargetChanger (ai fight)
bool melee; // used by kModernDudeTargetChanger (ai fight)
bool annoying; // used by kModernDudeTargetChanger (ai fight)
};
struct TRPLAYERCTRL { // this one for controlling the player using triggers (movement speed, jumps and other stuff)
@ -144,19 +158,23 @@ struct TRPLAYERCTRL { // this one for controlling the player using triggers (mov
// - VARIABLES ------------------------------------------------------------------
extern bool gModernMap;
extern bool gTeamsSpawnUsed;
extern bool gEventRedirectsUsed;
extern ZONE gStartZoneTeam1[kMaxPlayers];
extern ZONE gStartZoneTeam2[kMaxPlayers];
extern THINGINFO_EXTRA gThingInfoExtra[kThingMax];
extern VECTORINFO_EXTRA gVectorInfoExtra[kVectorMax];
extern MISSILEINFO_EXTRA gMissileInfoExtra[kMissileMax];
extern DUDEINFO_EXTRA gDudeInfoExtra[kDudeMax];
extern TRPLAYERCTRL gPlayerCtrl[kMaxPlayers];
extern SPRITEMASS gSpriteMass[kMaxXSprites];
extern short gProxySpritesList[kMaxSuperXSprites];
extern short gSightSpritesList[kMaxSuperXSprites];
extern short gPhysSpritesList[kMaxSuperXSprites];
extern short gImpactSpritesList[kMaxSuperXSprites];
extern short gProxySpritesCount;
extern short gSightSpritesCount;
extern short gPhysSpritesCount;
extern short gImpactSpritesCount;
// - FUNCTIONS ------------------------------------------------------------------
bool nnExtEraseModernStuff(spritetype* pSprite, XSPRITE* pXSprite);
@ -164,6 +182,7 @@ void nnExtInitModernStuff(bool bSaveLoad);
void nnExtProcessSuperSprites(void);
bool nnExtIsImmune(spritetype* pSprite, int dmgType, int minScale = 16);
int nnExtRandom(int a, int b);
void nnExtResetGlobals();
// ------------------------------------------------------------------------- //
spritetype* randomDropPickupObject(spritetype* pSprite, short prevItem);
spritetype* randomSpawnDude(spritetype* pSprite);
@ -190,9 +209,7 @@ bool aiFightIsMeleeUnit(spritetype* pDude);
bool aiFightDudeIsAffected(XSPRITE* pXDude);
bool aiFightMatesHaveSameTarget(XSPRITE* pXLeader, spritetype* pTarget, int allow);
bool aiFightGetDudesForBattle(XSPRITE* pXSprite);
inline bool aiFightIsMateOf(XSPRITE* pXDude, XSPRITE* pXSprite) {
return (pXDude->rxID == pXSprite->rxID);
}
bool aiFightIsMateOf(XSPRITE* pXDude, XSPRITE* pXSprite);
void aiFightAlarmDudesInSight(spritetype* pSprite, int max);
void aiFightActivateDudes(int rx);
void aiFightFreeTargets(int nSprite);
@ -216,6 +233,10 @@ void useSectorLigthChanger(XSPRITE* pXSource, XSECTOR* pXSector);
void useTargetChanger(XSPRITE* pXSource, spritetype* pSprite);
void usePictureChanger(XSPRITE* pXSource, int objType, int objIndex);
void usePropertiesChanger(XSPRITE* pXSource, short objType, int objIndex);
void useSequentialTx(XSPRITE* pXSource, COMMAND_ID cmd, bool setState);
void useRandomTx(XSPRITE* pXSource, COMMAND_ID cmd, bool setState);
bool txIsRanged(XSPRITE* pXSource);
void seqTxSendCmdAll(XSPRITE* pXSource, int nIndex, COMMAND_ID cmd, bool modernSend);
// ------------------------------------------------------------------------- //
void trPlayerCtrlLink(XSPRITE* pXSource, PLAYER* pPlayer);
void trPlayerCtrlSetRace(XSPRITE* pXSource, PLAYER* pPlayer);
@ -265,6 +286,8 @@ void windGenStopWindOnSectors(XSPRITE* pXSource);
int getSpriteMassBySize(spritetype* pSprite);
bool ceilIsTooLow(spritetype* pSprite);
void levelEndLevelCustom(int nLevel);
XSPRITE* eventRedirected(int objType, int objXIndex, bool byRx);
bool pointingAt(XSPRITE* pXSource, int destType);
#endif
////////////////////////////////////////////////////////////////////////

View file

@ -2148,7 +2148,9 @@ void trInit(void)
case kModernRandom:
case kModernRandom2:
if (!gModernMap || pXSprite->state == pXSprite->restState) break;
else evPost(i, 3, (120 * pXSprite->busyTime) / 10, kCmdRepeat);
evPost(i, 3, (120 * pXSprite->busyTime) / 10, kCmdRepeat);
if (pXSprite->waitTime > 0)
evPost(i, 3, (pXSprite->waitTime * 120) / 10, pXSprite->restState ? kCmdOn : kCmdOff);
break;
case kModernSeqSpawner:
case kModernObjDataAccumulator:
@ -2156,7 +2158,9 @@ void trInit(void)
case kModernEffectSpawner:
case kModernWindGenerator:
if (pXSprite->state == pXSprite->restState) break;
else evPost(i, 3, 0, kCmdRepeat);
evPost(i, 3, 0, kCmdRepeat);
if (pXSprite->waitTime > 0)
evPost(i, 3, (pXSprite->waitTime * 120) / 10, pXSprite->restState ? kCmdOn : kCmdOff);
break;
#endif
case kGenTrigger: