- Fixed getPlayeById() function in multiplayer.

- Fixed debris physics flags was not properly reset on level restart.
- Added new modern type "kModernSlopeChanger" that can manipulate sector and sprite slopes.
- Allow to drop items and keys for players in multiplayer (gModernMap only).
- Added event commands to manipulate dude flags.
- Patrol enemies (xsprite.dudeFlag4, gModernMap only):
  - Added path markers following.
  - Added stealth mechanics.
  - Added spot target progress bar.
  - Added alarm dude flag.
  - Added blind dude flag.
  - Added deaf dude flag.
  - Added conditions for kModernCondition related to patrol enemies.
- kModernDamager can work like generator and damage anyone in sectors or in map.
- kSectorDamage is not does the damage if in Off state (gModernMap only).
- Additional options kModernSeqSpawner.
- Effects that created with kModernEffectSpawner now inherits offset of the sprite.
- Added kCmdSectorMotionPause and kCmdSectorMotionContinue event commands that allows to pause or continue sector motion (gModernMap only, WIP).
- Various minor fixes.

# Conflicts:
#	source/blood/src/ai.cpp
#	source/blood/src/common_game.h
#	source/blood/src/eventq.cpp
#	source/blood/src/nnexts.cpp
#	source/blood/src/nnexts.h
#	source/blood/src/triggers.cpp
#	source/blood/src/triggers.h
#	source/blood/src/view.cpp

# Conflicts:
#	source/games/blood/src/ai.cpp
#	source/games/blood/src/nnexts.h

# Conflicts:
#	source/games/blood/src/actor.cpp
#	source/games/blood/src/ai.cpp
This commit is contained in:
NoOneBlood 2020-12-06 23:56:09 +03:00 committed by Christoph Oelckers
parent c4fa99c891
commit 3a59243ea0
13 changed files with 1508 additions and 234 deletions

View file

@ -4193,8 +4193,14 @@ static void actTouchFloor(DBloodActor* actor, int nSector)
XSECTOR* pXSector = nullptr;
if (pSector->extra > 0) pXSector = &xsector[pSector->extra];
if (pXSector && (pSector->type == kSectorDamage || pXSector->damageType > 0))
{
bool doDamage = (pXSector && (pSector->type == kSectorDamage || pXSector->damageType > 0));
// don't allow damage for damage sectors if they are not enabled
#ifdef NOONE_EXTENSIONS
if (gModernMap && doDamage && pSector->type == kSectorDamage && !pXSector->state)
doDamage = false;
#endif
if (doDamage) {
DAMAGE_TYPE nDamageType;
if (pSector->type == kSectorDamage) nDamageType = (DAMAGE_TYPE)ClipRange(pXSector->damageType, DAMAGE_TYPE_0, DAMAGE_TYPE_6);
else nDamageType = (DAMAGE_TYPE)ClipRange(pXSector->damageType - 1, DAMAGE_TYPE_0, DAMAGE_TYPE_6);

View file

@ -893,13 +893,126 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType
{
spritetype *pSource = &source->s();
int nSource = pSource->index;
if (pSprite == pSource)
return 0;
if (pXSprite->target == -1 || (nSource != pXSprite->target && Chance(pSprite->type == pSource->type ? nDamage*pDudeInfo->changeTargetKin : nDamage*pDudeInfo->changeTarget)))
if (pSprite == pSource) return 0;
else if (pXSprite->target == -1 || (nSource != pXSprite->target && Chance(pSprite->type == pSource->type ? nDamage*pDudeInfo->changeTargetKin : nDamage*pDudeInfo->changeTarget)))
{
aiSetTarget(pXSprite, nSource);
aiActivateDude(&bloodActors[pXSprite->reference]);
}
#ifdef NOONE_EXTENSIONS
if (gModernMap) {
// for enemies in patrol mode
if (aiInPatrolState(pXSprite->aiState)) {
aiPatrolStop(pSprite, pSource->index, pXSprite->dudeAmbush);
PLAYER* pPlayer = getPlayerById(pSource->type);
if (!pPlayer) return nDamage;
if (powerupCheck(pPlayer, kPwUpShadowCloak)) pPlayer->pwUpTime[kPwUpShadowCloak] = 0;
if (readyForCrit(pSource, pSprite)) {
nDamage += aiDamageSprite(pSprite, pXSprite, pSource->index, nDmgType, nDamage * (10 - gGameOptions.nDifficulty));
if (pXSprite->health > 0) {
int fullHp = (pXSprite->sysData2 > 0) ? ClipRange(pXSprite->sysData2 << 4, 1, 65535) : getDudeInfo(pSprite->type)->startHealth << 4;
if (((100 * pXSprite->health) / fullHp) <= 75) {
cumulDamage[pSprite->extra] += nDamage << 4; // to be sure any enemy will play the recoil animation
RecoilDude(pSprite, pXSprite);
}
}
consoleSysMsg("Player #%d does the critical damage to patrol dude #%d!", pPlayer->nPlayer + 1, pSprite->index);
}
return nDamage;
}
if (pSprite->type == kDudeModernCustomBurning) {
if (Chance(0x2000) && gDudeExtra[pSprite->extra].at0 < (int)gFrameClock) {
playGenDudeSound(pSprite, kGenDudeSndBurning);
gDudeExtra[pSprite->extra].at0 = (int)gFrameClock + 360;
}
if (pXSprite->burnTime == 0) pXSprite->burnTime = 2400;
if (spriteIsUnderwater(pSprite, false)) {
pSprite->type = kDudeModernCustom;
pXSprite->burnTime = 0;
pXSprite->health = 1; // so it can be killed with flame weapons while underwater and if already was burning dude before.
aiGenDudeNewState(pSprite, &genDudeGotoW);
}
return nDamage;
}
if (pSprite->type == kDudeModernCustom) {
GENDUDEEXTRA* pExtra = genDudeExtra(pSprite);
if (nDmgType == DAMAGE_TYPE_1) {
if (pXSprite->health > pDudeInfo->fleeHealth) return nDamage;
else if (pXSprite->txID <= 0 || getNextIncarnation(pXSprite) == NULL) {
removeDudeStuff(pSprite);
if (pExtra->weaponType == kGenDudeWeaponKamikaze)
doExplosion(pSprite, pXSprite->data1 - kTrapExploder);
if (spriteIsUnderwater(pSprite)) {
pXSprite->health = 0;
return nDamage;
}
if (pXSprite->burnTime <= 0)
pXSprite->burnTime = 1200;
if (pExtra->canBurn && pExtra->availDeaths[DAMAGE_TYPE_1] > 0) {
aiPlay3DSound(pSprite, 361, AI_SFX_PRIORITY_0, -1);
playGenDudeSound(pSprite, kGenDudeSndBurning);
pSprite->type = kDudeModernCustomBurning;
if (pXSprite->data2 == kGenDudeDefaultSeq) // don't inherit palette for burning if using default animation
pSprite->pal = 0;
aiGenDudeNewState(pSprite, &genDudeBurnGoto);
actHealDude(pXSprite, dudeInfo[55].startHealth, dudeInfo[55].startHealth);
gDudeExtra[pSprite->extra].at0 = (int)gFrameClock + 360;
evKill(nSprite, 3, kCallbackFXFlameLick);
}
} else {
actKillDude(nSource, pSprite, DAMAGE_TYPE_0, 65535);
}
} else if (canWalk(pSprite) && !inDodge(pXSprite->aiState) && !inRecoil(pXSprite->aiState)) {
if (!dudeIsMelee(pXSprite)) {
if (inIdle(pXSprite->aiState) || Chance(getDodgeChance(pSprite))) {
if (!spriteIsUnderwater(pSprite)) {
if (!canDuck(pSprite) || !sub_5BDA8(pSprite, 14)) aiGenDudeNewState(pSprite, &genDudeDodgeShortL);
else aiGenDudeNewState(pSprite, &genDudeDodgeShortD);
if (Chance(0x0200))
playGenDudeSound(pSprite, kGenDudeSndGotHit);
} else if (sub_5BDA8(pSprite, 13)) {
aiGenDudeNewState(pSprite, &genDudeDodgeShortW);
}
}
} else if (Chance(0x0200)) {
playGenDudeSound(pSprite, kGenDudeSndGotHit);
}
}
return nDamage;
}
}
#endif
if (nDmgType == DAMAGE_TYPE_6)
{
DUDEEXTRA *pDudeExtra = &gDudeExtra[pSprite->extra];
@ -985,79 +1098,6 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType
evKill(nSprite, 3, kCallbackFXFlameLick);
}
break;
#ifdef NOONE_EXTENSIONS
case kDudeModernCustomBurning:
if (Chance(0x2000) && gDudeExtra[pSprite->extra].time < PlayClock) {
playGenDudeSound(pSprite, kGenDudeSndBurning);
gDudeExtra[pSprite->extra].time = PlayClock + 360;
}
if (pXSprite->burnTime == 0) pXSprite->burnTime = 2400;
if (spriteIsUnderwater(pSprite, false)) {
pSprite->type = kDudeModernCustom;
pXSprite->burnTime = 0;
pXSprite->health = 1; // so it can be killed with flame weapons while underwater and if already was burning dude before.
aiGenDudeNewState(pSprite, &genDudeGotoW);
}
break;
case kDudeModernCustom: {
GENDUDEEXTRA* pExtra = genDudeExtra(pSprite);
if (nDmgType == DAMAGE_TYPE_1) {
if (pXSprite->health > (unsigned)pDudeInfo->fleeHealth) break;
else if (pXSprite->txID <= 0 || getNextIncarnation(pXSprite) == NULL) {
removeDudeStuff(pSprite);
if (pExtra->weaponType == kGenDudeWeaponKamikaze)
doExplosion(pSprite, pXSprite->data1 - kTrapExploder);
if (spriteIsUnderwater(pSprite, false)) {
pXSprite->health = 0;
break;
}
if (pXSprite->burnTime <= 0)
pXSprite->burnTime = 1200;
if (pExtra->canBurn && pExtra->availDeaths[DAMAGE_TYPE_1] > 0) {
aiPlay3DSound(pSprite, 361, AI_SFX_PRIORITY_0, -1);
playGenDudeSound(pSprite, kGenDudeSndBurning);
pSprite->type = kDudeModernCustomBurning;
if (pXSprite->data2 == kGenDudeDefaultSeq) // don't inherit palette for burning if using default animation
pSprite->pal = 0;
aiGenDudeNewState(pSprite, &genDudeBurnGoto);
actHealDude(pXSprite, dudeInfo[55].startHealth, dudeInfo[55].startHealth);
gDudeExtra[pSprite->extra].time = PlayClock + 360;
evKill(nSprite, 3, kCallbackFXFlameLick);
}
} else {
actKillDude(nSource, pSprite, DAMAGE_TYPE_0, 65535);
}
} else if (canWalk(pSprite) && !inDodge(pXSprite->aiState) && !inRecoil(pXSprite->aiState)) {
if (!dudeIsMelee(pXSprite)) {
if (inIdle(pXSprite->aiState) || Chance(getDodgeChance(pSprite))) {
if (!spriteIsUnderwater(pSprite, false)) {
if (!canDuck(pSprite) || !dudeIsPlayingSeq(pSprite, 14)) aiGenDudeNewState(pSprite, &genDudeDodgeShortL);
else aiGenDudeNewState(pSprite, &genDudeDodgeShortD);
if (Chance(0x0200))
playGenDudeSound(pSprite, kGenDudeSndGotHit);
} else if (dudeIsPlayingSeq(pSprite, 13)) {
aiGenDudeNewState(pSprite, &genDudeDodgeShortW);
}
}
} else if (Chance(0x0200)) {
playGenDudeSound(pSprite, kGenDudeSndGotHit);
}
}
break;
}
#endif
case kDudeCultistBeast:
if (pXSprite->health <= (unsigned int)pDudeInfo->fleeHealth)
{
@ -1515,17 +1555,25 @@ void aiInitSprite(spritetype *pSprite)
DUDEEXTRA *pDudeExtra = &gDudeExtra[pSprite->extra];
pDudeExtra->recoil = 0;
pDudeExtra->time = 0;
#ifdef NOONE_EXTENSIONS
int stateTimer = -1, targetMarker = -1;
int targetX = 0, targetY = 0, targetZ = 0;
// dude patrol init
if (gModernMap) {
// must keep it in case of loading save
if (pXSprite->dudeFlag4 && spriRangeIsFine(pXSprite->target) && sprite[pXSprite->target].type == kMarkerPath) {
stateTimer = pXSprite->stateTimer; targetMarker = pXSprite->target;
targetX = pXSprite->targetX; targetY = pXSprite->targetY;
targetZ = pXSprite->targetZ;
}
}
#endif
switch (pSprite->type) {
#ifdef NOONE_EXTENSIONS
case kDudeModernCustom:
aiGenDudeInitSprite(pSprite, pXSprite);
genDudePrepare(pSprite, kGenDudePropertyAll);
return;
case kDudeModernCustomBurning:
aiGenDudeInitSprite(pSprite, pXSprite);
return;
#endif
case kDudeCultistTommy:
case kDudeCultistShotgun:
case kDudeCultistTesla:
@ -1739,6 +1787,45 @@ void aiInitSprite(spritetype *pSprite)
pSprite->flags = 15;
break;
}
#ifdef NOONE_EXTENSIONS
if (gModernMap) {
if (pSprite->type == kDudeModernCustom) {
aiGenDudeInitSprite(pSprite, pXSprite);
genDudePrepare(pSprite, kGenDudePropertyAll);
}
if (pXSprite->dudeFlag4) {
// restore dude's path
if (spriRangeIsFine(targetMarker)) {
pXSprite->target = targetMarker;
pXSprite->targetX = targetX;
pXSprite->targetY = targetY;
pXSprite->targetZ = targetZ;
}
// reset target spot progress
pXSprite->data3 = 0;
// make dude follow the markers
bool uwater = spriteIsUnderwater(pSprite);
if (stateTimer > 0) {
if (uwater) aiPatrolState(pSprite, kAiStatePatrolWaitW);
else if (pXSprite->unused2) aiPatrolState(pSprite, kAiStatePatrolWaitC);
else aiPatrolState(pSprite, kAiStatePatrolWaitL);
pXSprite->stateTimer = stateTimer; // restore state timer
}
else if (uwater) aiPatrolState(pSprite, kAiStatePatrolMoveW);
else if (pXSprite->unused2) aiPatrolState(pSprite, kAiStatePatrolMoveC);
else aiPatrolState(pSprite, kAiStatePatrolMoveL);
}
}
#endif
}
//---------------------------------------------------------------------------

View file

@ -251,6 +251,7 @@ void Respawn(int nSprite) // 9
#ifdef NOONE_EXTENSIONS
if (!gModernMap || pXSprite->sysData2 <= 0) pXSprite->health = dudeInfo[pSprite->type - kDudeBase].startHealth << 4;
else pXSprite->health = ClipRange(pXSprite->sysData2 << 4, 1, 65535);
switch (pSprite->type) {
default:
pSprite->clipdist = getDudeInfo(nType + kDudeBase)->clipdist;
@ -261,6 +262,12 @@ void Respawn(int nSprite) // 9
seqSpawn(genDudeSeqStartId(pXSprite), 3, pSprite->extra, -1);
break;
}
// return dude to the patrol state
if (gModernMap && pXSprite->dudeFlag4) {
pXSprite->data3 = 0;
pXSprite->target = -1;
}
#else
pSprite->clipdist = getDudeInfo(nType + kDudeBase)->clipdist;
pXSprite->health = getDudeInfo(nType + kDudeBase)->startHealth << 4;

View file

@ -51,7 +51,7 @@ enum
kExplodeMax = 8,
kLensSize = 80,
kViewEffectMax = 19,
kViewEffectMax = 20,
kNoTile = -1,
@ -401,6 +401,14 @@ kAiStateSearch = 3,
kAiStateChase = 4,
kAiStateRecoil = 5,
kAiStateAttack = 6,
kAiStatePatrolBase = 7,
kAiStatePatrolWaitL = kAiStatePatrolBase,
kAiStatePatrolWaitC,
kAiStatePatrolWaitW,
kAiStatePatrolMoveL,
kAiStatePatrolMoveC,
kAiStatePatrolMoveW,
kAiStatePatrolMax,
};
enum

View file

@ -1553,7 +1553,7 @@ DUDEINFO dudeInfo[kDudeMax-kDudeBase] =
20,
10240, // hear distance
51200, // seeing distance
kAng120, // vision periphery
kAng90, // vision periphery
// 0,
618, // melee distance
5, // flee health
@ -1561,7 +1561,7 @@ DUDEINFO dudeInfo[kDudeMax-kDudeBase] =
0x0000, // change target chance
0x0000, // change target to kin chance
0x8000, // alertChance
0, // lockout
1, // lockout
46603, // frontSpeed
34952, // sideSpeed
13981, // backSpeed

View file

@ -458,7 +458,7 @@ void evSend(int nIndex, int nType, int rxId, COMMAND_ID command)
PLAYER* pPlayer = NULL;
if (playerRXRngIsFine(rxId))
{
if ((pPlayer = getPlayerById((kChannelPlayer0 - kChannelPlayer7) + kMaxPlayers)) != nullptr)
if ((pPlayer = getPlayerById((rxId - kChannelPlayer7) + kMaxPlayers)) != nullptr)
trMessageSprite(pPlayer->nSprite, event);
}
else if (rxId == kChannelAllPlayers)
@ -468,6 +468,7 @@ void evSend(int nIndex, int nType, int rxId, COMMAND_ID command)
if ((pPlayer = getPlayerById(i)) != nullptr)
trMessageSprite(pPlayer->nSprite, event);
}
return;
}
}

View file

@ -97,6 +97,7 @@ kCmdCounterSector = 12,
kCmdCallback = 20,
kCmdRepeat = 21,
kCmdSpritePush = 30,
kCmdSpriteImpact = 31,
kCmdSpritePickup = 32,
@ -113,8 +114,20 @@ kCmdSectorExit = 43,
kCmdWallPush = 50,
kCmdWallImpact = 51,
kCmdWallTouch = 52,
#ifdef NOONE_EXTENSIONS
kCmdSectorMotionPause = 13, // stops motion of the sector
kCmdSectorMotionContinue = 14, // continues motion of the sector
kCmdModernUse = 53, // used by most of modern types
kCmdModernPatrolOff = 54, // to manipulate dudeFlags
kCmdModernPatrolOn = 55, // to manipulate dudeFlags
kCmdModernDeafOff = 56, // to manipulate dudeFlags
kCmdModernDeafOn = 57, // to manipulate dudeFlags
kCmdModernBlindOff = 58, // to manipulate dudeFlags
kCmdModernBlindOn = 59, // to manipulate dudeFlags
kCmdModernAlarmOff = 60, // to manipulate dudeFlags
kCmdModernAlarmOn = 61, // to manipulate dudeFlags
#endif
kCmdModernUse = 53, // used by most of modern types
kCmdNumberic = 64, // 64: 0, 65: 1 and so on up to 255
kCmdModernFeaturesEnable = 100, // must be in object with kChannelMapModernize RX / TX
kCmdModernFeaturesDisable = 200, // must be in object with kChannelMapModernize RX / TX

File diff suppressed because it is too large Load diff

View file

@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "actor.h"
#include "dude.h"
#include "player.h"
#include "triggers.h"
BEGIN_BLD_NS
@ -66,6 +67,11 @@ enum
kCondRange = 100,
};
#define kPatrolStateSize 27
#define kMaxPatrolVelocity 500000
#define kMaxPatrolCrouchVelocity (kMaxPatrolVelocity >> 1)
#define kMaxPatrolSpotValue 500
// modern statnums
@ -83,6 +89,7 @@ kStatModernMax = 40,
// modern sprite types
enum {
kModernSlopeChanger = 16,
kModernCustomDudeSpawn = 24,
kModernRandomTX = 25,
kModernSequentialTX = 26,
@ -185,7 +192,12 @@ struct MISSILEINFO_EXTRA {
struct DUDEINFO_EXTRA {
bool flying; // used by kModernDudeTargetChanger (ai fight)
bool melee; // used by kModernDudeTargetChanger (ai fight)
bool annoying; // used by kModernDudeTargetChanger (ai fight)
int idlgseqofs : 6; // used for patrol
int mvegseqofs : 6; // used for patrol
int idlwseqofs : 6; // used for patrol
int mvewseqofs : 6; // used for patrol
int idlcseqofs : 6; // used for patrol
int mvecseqofs : 6; // used for patrol
};
struct TRPLAYERCTRL { // this one for controlling the player using triggers (movement speed, jumps and other stuff)
@ -228,6 +240,7 @@ extern short gSightSpritesCount;
extern short gPhysSpritesCount;
extern short gImpactSpritesCount;
extern short gTrackingCondsCount;
extern AISTATE genPatrolStates[kPatrolStateSize];
// - FUNCTIONS ------------------------------------------------------------------
bool nnExtEraseModernStuff(spritetype* pSprite, XSPRITE* pXSprite);
@ -271,15 +284,16 @@ spritetype* aiFightGetTargetInRange(spritetype* pSprite, int minDist, int maxDis
spritetype* aiFightTargetIsPlayer(XSPRITE* pXSprite);
spritetype* aiFightGetMateTargets(XSPRITE* pXSprite);
// ------------------------------------------------------------------------- //
void useSlopeChanger(XSPRITE* pXSource, int objType, int objIndex);
void useSectorWindGen(XSPRITE* pXSource, sectortype* pSector);
void useEffectGen(XSPRITE* pXSource, spritetype* pSprite);
void useSeqSpawnerGen(XSPRITE* pXSource, int objType, int index);
void useSpriteDamager(XSPRITE* pXSource, spritetype* pSprite);
void damageSprites(XSPRITE* pXSource, spritetype* pSprite);
void useTeleportTarget(XSPRITE* pXSource, spritetype* pSprite);
void useObjResizer(XSPRITE* pXSource, short objType, int objIndex);
void useRandomItemGen(spritetype* pSource, XSPRITE* pXSource);
void useUniMissileGen(int, int nXSprite);
void useSoundGen(spritetype* pSource, XSPRITE* pXSource);
void useSoundGen(XSPRITE* pXSource, spritetype* pSprite);
void useIncDecGen(XSPRITE* pXSource, short objType, int objIndex);
void useDataChanger(XSPRITE* pXSource, int objType, int objIndex);
void useSectorLigthChanger(XSPRITE* pXSource, XSECTOR* pXSector);
@ -305,6 +319,7 @@ void trPlayerCtrlUsePackItem(XSPRITE* pXSource, PLAYER* pPlayer, int evCmd);
// ------------------------------------------------------------------------- //
void modernTypeTrigger(int type, int nDest, EVENT event);
char modernTypeSetSpriteState(int nSprite, XSPRITE* pXSprite, int nState);
bool modernTypeOperateSector(int nSector, sectortype* pSector, XSECTOR* pXSector, EVENT event);
bool modernTypeOperateSprite(int nSprite, spritetype* pSprite, XSPRITE* pXSprite, EVENT event);
bool modernTypeOperateWall(int nWall, walltype* pWall, XWALL* pXWall, EVENT event);
void modernTypeSendCommand(int nSprite, int channel, COMMAND_ID command);
@ -355,6 +370,20 @@ XSPRITE* evrListRedirectors(int objType, int objXIndex, XSPRITE* pXRedir, int* t
XSPRITE* evrIsRedirector(int nSprite);
int listTx(XSPRITE* pXRedir, int tx);
void seqSpawnerOffSameTx(XSPRITE* pXSource);
// ------------------------------------------------------------------------- //
void aiPatrolSetMarker(spritetype* pSprite, XSPRITE* pXSprite);
void aiPatrolThink(spritetype* pSprite, XSPRITE* pXSprite);
void aiPatrolStop(spritetype* pSprite, int target, bool alarm = false);
void aiPatrolAlarm(spritetype* pSprite, bool chain);
void aiPatrolState(spritetype* pSprite, int state);
void aiPatrolMove(spritetype* pSprite, XSPRITE* pXSprite);
int aiPatrolMarkerBusy(int nExcept, int nMarker);
bool aiPatrolMarkerReached(spritetype* pSprite, XSPRITE* pXSprite);
AISTATE* aiInPatrolState(AISTATE* pAiState);
// ------------------------------------------------------------------------- //
bool readyForCrit(spritetype* pHunter, spritetype* pVictim);
int sectorInMotion(int nSector);
#endif
////////////////////////////////////////////////////////////////////////
// This file provides modern features for mappers.

View file

@ -2017,6 +2017,32 @@ int playerDamageSprite(DBloodActor* source, PLAYER *pPlayer, DAMAGE_TYPE nDamage
}
FragPlayer(pPlayer, nSource);
trTriggerSprite(nSprite, pXSprite, kCmdOff);
#ifdef NOONE_EXTENSIONS
// allow drop items and keys in multiplayer
if (gModernMap && gGameOptions.nGameType != 0 && pPlayer->pXSprite->health <= 0) {
spritetype* pItem = NULL;
if (pPlayer->pXSprite->dropMsg && (pItem = actDropItem(pPlayer->pSprite, pPlayer->pXSprite->dropMsg)) != NULL)
evPost(pItem->index, OBJ_SPRITE, 500, kCallbackRemove);
if (pPlayer->pXSprite->key) {
int i; // if all players have this key, don't drop it
for (i = connecthead; i >= 0; i = connectpoint2[i]) {
if (!gPlayer[i].hasKey[pPlayer->pXSprite->key])
break;
}
if (i == 0 && (pItem = actDropKey(pPlayer->pSprite, (pPlayer->pXSprite->key + kItemKeyBase) - 1)) != NULL)
evPost(pItem->index, OBJ_SPRITE, 500, kCallbackRemove);
}
}
#endif
}
assert(getSequence(pDudeInfo->seqStartID + nDeathSeqID) != NULL);
seqSpawn(pDudeInfo->seqStartID+nDeathSeqID, 3, nXSprite, nKneelingPlayer);

View file

@ -132,26 +132,7 @@ char SetSectorState(int nSector, XSECTOR *pXSector, int nState)
}
int gBusyCount = 0;
enum BUSYID {
BUSYID_0 = 0,
BUSYID_1,
BUSYID_2,
BUSYID_3,
BUSYID_4,
BUSYID_5,
BUSYID_6,
BUSYID_7,
};
struct BUSY {
int index;
int delta;
int busy;
int type;
};
BUSY gBusy[128];
BUSY gBusy[];
void AddBusy(int a1, BUSYID a2, int nDelta)
{
@ -164,7 +145,7 @@ void AddBusy(int a1, BUSYID a2, int nDelta)
}
if (i == gBusyCount)
{
if (gBusyCount == 128)
if (gBusyCount == kMaxBusyCount)
return;
gBusy[i].index = a1;
gBusy[i].type = a2;
@ -1544,22 +1525,10 @@ void OperateSector(unsigned int nSector, XSECTOR *pXSector, EVENT event)
sectortype *pSector = &sector[nSector];
#ifdef NOONE_EXTENSIONS
if (gModernMap) {
switch (pSector->type) {
// reset counter sector state and make it work again after unlock, so it can be used again.
case kSectorCounter:
switch (event.cmd) {
case kCmdUnlock:
case kCmdToggleLock:
if (pXSector->locked != 1) break;
SetSectorState(nSector, pXSector, 0);
evPost(nSector, 6, 0, kCallbackCounterCheck);
break;
}
break;
}
}
if (gModernMap && modernTypeOperateSector(nSector, pSector, pXSector, event))
return;
#endif
switch (event.cmd) {
case kCmdLock:
pXSector->locked = 1;
@ -1583,6 +1552,9 @@ void OperateSector(unsigned int nSector, XSECTOR *pXSector, EVENT event)
pXSector->stopOff = 1;
break;
default:
#ifdef NOONE_EXTENSIONS
if (gModernMap && pXSector->unused1) break;
#endif
switch (pSector->type) {
case kSectorZMotionSprite:
OperateDoor(nSector, pXSector, event, BUSYID_1);
@ -1992,9 +1964,15 @@ void trProcessBusy(void)
memset(velCeil, 0, sizeof(velCeil));
for (int i = gBusyCount-1; i >= 0; i--)
{
int oldBusy = gBusy[i].busy;
gBusy[i].busy = ClipRange(oldBusy+gBusy[i].delta*4, 0, 65536);
int nStatus = gBusyProc[gBusy[i].type](gBusy[i].index, gBusy[i].busy);
int nStatus;
int oldBusy = gBusy[i].at8;
gBusy[i].at8 = ClipRange(oldBusy+gBusy[i].at4*4, 0, 65536);
#ifdef NOONE_EXTENSIONS
if (!gModernMap || !xsector[sector[gBusy[i].at0].extra].unused1) nStatus = gBusyProc[gBusy[i].atc](gBusy[i].at0, gBusy[i].at8);
else nStatus = 3; // allow to pause/continue motion for sectors any time by sending special command
#else
nStatus = gBusyProc[gBusy[i].atc](gBusy[i].at0, gBusy[i].at8);
#endif
switch (nStatus) {
case 1:
gBusy[i].busy = oldBusy;

View file

@ -29,7 +29,31 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "dude.h"
#include "player.h"
BEGIN_BLD_NS
enum BUSYID {
BUSYID_0 = 0,
BUSYID_1,
BUSYID_2,
BUSYID_3,
BUSYID_4,
BUSYID_5,
BUSYID_6,
BUSYID_7,
};
#define kMaxBusyCount 128
struct BUSY {
int index;
int delta;
int busy;
/* int at0;
int at4;
int at8;*/
BUSYID atc;
};
extern BUSY gBusy[kMaxBusyCount];
extern int gBusyCount;
void trTriggerSector(unsigned int nSector, XSECTOR *pXSector, int command);
void trMessageSector(unsigned int nSector, EVENT event);
void trTriggerWall(unsigned int nWall, XWALL *pXWall, int command);
@ -42,6 +66,9 @@ void trInit(void);
void trTextOver(int nId);
char SetSpriteState(int nSprite, XSPRITE* pXSprite, int nState);
char SetWallState(int nWall, XWALL* pXWall, int nState);
char SetSectorState(int nSector, XSECTOR* pXSector, int nState);
void TeleFrag(int nKiller, int nSector);
void SectorStartSound(int nSector, int nState);
void SectorEndSound(int nSector, int nState);
END_BLD_NS

View file

@ -95,6 +95,7 @@ enum VIEW_EFFECT {
VIEW_EFFECT_16,
VIEW_EFFECT_17,
VIEW_EFFECT_18,
kViewEffectSpotProgress,
};
enum VIEWPOS {